Python進階(3)_進程與線程中的lock(互斥鎖、遞迴鎖、訊號量)

來源:互聯網
上載者:User

標籤:time   同步鎖   有一個   共用資料   互斥   global   semaphore   int   cti   

1、同步鎖 (Lock)

當各個線程需要訪問一個公用資源時,會出現資料紊亂

例如:

 1 import threading,time 2 def sub(): 3     global num         #對全域變數進行操作 4  5     temp=num 6     time.sleep(0.001)    #類比線程執行中出現I/o延遲等 7     num=temp-1           #所有線程對全域變數進行減一 8  9     time.sleep(1)10 11 num=10012 l=[]13 14 for i in range(100):15     t=threading.Thread(target=sub,args=())16     t.start()17     l.append(t)18 19 for obj in l:20     obj.join()21 22 print(num)          23 24 #執行結果不可預期:25 >>:9026 >>:9327 >>:9228 

  當全域資源(counter)被搶佔的情況,問題產生的原因就是沒有控制多個線程對同一資源的訪問,對資料造成破壞,使得線程啟動並執行結果不可預期。這種現象稱為“線程不安全”。在開發過程中我們必須要避免這種情況,那怎麼避免?這就用到了互斥鎖了。

互斥鎖概念

  Python編程中,引入了對象互斥鎖的概念,來保證共用資料操作的完整性。每個對象都對應於一個可稱為” 互斥鎖” 的標記,這個標記用來保證在任一時刻,只能有一個線程訪問該對象。在Python中我們使用threading模組提供的Lock類。

  我們對上面的程式進行整改,為此我們需要添加一個互斥鎖變數lock = threading.Lock(),然後在爭奪資源的時候之前我們會先搶佔這把鎖lock.acquire(),對資源使用完成之後我們在釋放這把鎖mutex.release()。

代碼如下:

import threading,timedef sub():    global num    lock.acquire()    temp=num    time.sleep(0.01)    num=temp-1    lock.release()    time.sleep(1)num=100l=[]lock=threading.Lock()for i in range(100):    t=threading.Thread(target=sub,args=())    t.start()    l.append(t)for obj in l:    obj.join()print(num)
2、死結與遞迴鎖

  所謂死結: 是指兩個或兩個以上的進程或線程在執行過程中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去。此時稱系統處於死結狀態或系統產生了死結,這些永遠在互相等待的進程稱為死結進程。 

 

會產生死結的例子:

class MyThread(threading.Thread):    def __init__(self):        threading.Thread.__init__(self)    def run(self):        self.foo()    def foo(self):        LockA.acquire()        print(‘I am %s GET LOCKA---------%s‘%(self.name,time.ctime()))        LockB.acquire()        print(‘I am %s GET LOCKB---------%s‘ % (self.name, time.ctime()))        LockB.release()        LockA.release()LockA=threading.Lock()LockB=threading.Lock()for i in range(10):    t=MyThread()    t.start()
使用遞迴鎖解決:

  在Python中為了支援在同一線程中多次請求同一資源,python提供了可重新進入鎖RLock。這個RLock內部維護著一個Lock和一個counter變數,counter記錄了acquire的次數,從而使得資源可以被多次require。直到一個線程所有的acquire都被release,其他的線程才能獲得資源。上面的例子如果使用RLock代替Lock,則不會發生死結:

class MyThread(threading.Thread):    def __init__(self):        threading.Thread.__init__(self)    def run(self):        self.foo()        self.bar()    def foo(self):        RLock.acquire()        print(‘I am %s GET LOCKA---------%s‘%(self.name,time.ctime()))        RLock.acquire()        print(‘I am %s GET LOCKB---------%s‘ % (self.name, time.ctime()))        RLock.release()        RLock.release()    def bar(self):        RLock.acquire()        print(‘I am %s GET LOCKB---------%s‘ % (self.name, time.ctime()))        time.sleep(1)        RLock.acquire()        print(‘I am %s GET LOCKA---------%s‘ % (self.name, time.ctime()))        RLock.release()        RLock.release()RLock=threading.RLock()for i in range(10):    t=MyThread()    t.start()

  

3、Semaphore(訊號量)

Semaphore管理一個內建的計數器,
每當調用acquire()時內建計數器-1;
調用release() 時內建計數器+1;
計數器不能小於0;當計數器為0時,acquire()將阻塞線程直到其他線程調用release()。

執行個體:(同時只有5個線程可以獲得semaphore,即可以限制最大串連數為5):

 1 import threading 2 import time 3  4 semaphore = threading.Semaphore(5) 5  6 def func(): 7     if semaphore.acquire(): 8         print (threading.currentThread().getName() + ‘ get semaphore‘) 9         time.sleep(2)10         semaphore.release()11 12 for i in range(20):13   t1 = threading.Thread(target=func)14   t1.start()

 

Python進階(3)_進程與線程中的lock(互斥鎖、遞迴鎖、訊號量)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.