本篇文章給大家分享的是有關(guān)怎么解鎖Python中的死鎖機制,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
創(chuàng)新互聯(lián)公司成立于2013年,我們提供高端成都網(wǎng)站建設公司、成都網(wǎng)站制作、成都網(wǎng)站設計、網(wǎng)站定制、網(wǎng)絡營銷推廣、小程序設計、微信公眾號開發(fā)、網(wǎng)站推廣服務,提供專業(yè)營銷思路、內(nèi)容策劃、視覺設計、程序開發(fā)來完成項目落地,為成都高空作業(yè)車租賃企業(yè)提供源源不斷的流量和訂單咨詢。
死鎖
簡單來說,死鎖是一個資源被多次調(diào)用,而多次調(diào)用方都未能釋放該資源就會造成死鎖,這里結(jié)合例子說明下兩種常見的死鎖情況。
1、迭代死鎖
該情況是一個線程“迭代”請求同一個資源,直接就會造成死鎖:
import threading import time class MyThread(threading.Thread): def run(self): global num time.sleep(1) if mutex.acquire(1): num = num+1 msg = self.name+' set num to '+str(num) print msg mutex.acquire() mutex.release() mutex.release() num = 0 mutex = threading.Lock() def test(): for i in range(5): t = MyThread() t.start() if __name__ == '__main__': test()
上例中,在run函數(shù)的if判斷中第一次請求資源,請求后還未 release ,再次acquire,最終無法釋放,造成死鎖。這里例子中通過將print下面的兩行注釋掉就可以正常執(zhí)行了 ,除此之外也可以通過可重入鎖解決,后面會提到。
2、互相調(diào)用死鎖
上例中的死鎖是在同一個def函數(shù)內(nèi)多次調(diào)用造成的,另一種情況是兩個函數(shù)中都會調(diào)用相同的資源,互相等待對方結(jié)束的情況。如果兩個線程分別占有一部分資源并且同時等待對方的資源,就會造成死鎖。
import threading import time class MyThread(threading.Thread): def do1(self): global resA, resB if mutexA.acquire(): msg = self.name+' got resA' print msg if mutexB.acquire(1): msg = self.name+' got resB' print msg mutexB.release() mutexA.release() def do2(self): global resA, resB if mutexB.acquire(): msg = self.name+' got resB' print msg if mutexA.acquire(1): msg = self.name+' got resA' print msg mutexA.release() mutexB.release() def run(self): self.do1() self.do2() resA = 0 resB = 0 mutexA = threading.Lock() mutexB = threading.Lock() def test(): for i in range(5): t = MyThread() t.start() if __name__ == '__main__': test()
這個死鎖的示例稍微有點復雜。具體可以理下。
二、可重入鎖
為了支持在同一線程中多次請求同一資源,python提供了“可重入鎖”:threading.RLock。RLock內(nèi)部維護著一個Lock和一個counter變量,counter記錄了acquire的次數(shù),從而使得資源可以被多次require。直到一個線程所有的acquire都被release,其他的線程才能獲得資源。這里以例1為例,如果使用RLock代替Lock,則不會發(fā)生死鎖:
import threading import time class MyThread(threading.Thread): def run(self): global num time.sleep(1) if mutex.acquire(1): num = num+1 msg = self.name+' set num to '+str(num) print msg mutex.acquire() mutex.release() mutex.release() num = 0 mutex = threading.RLock() def test(): for i in range(5): t = MyThread() t.start() if __name__ == '__main__': test()
和上面那個例子的不同之處在于threading.Lock()換成了threading.RLock() 。
三、互斥鎖
python threading模塊有兩類鎖:互斥鎖(threading.Lock )和可重用鎖(threading.RLock)。兩者的用法基本相同,具體如下:
lock = threading.Lock() lock.acquire() dosomething…… lock.release()
RLock的用法是將threading.Lock()修改為threading.RLock()。便于理解,先來段代碼:
[root@361way lock]# cat lock1.py
#!/usr/bin/env python # coding=utf-8 import threading # 導入threading模塊 import time # 導入time模塊 class mythread(threading.Thread): # 通過繼承創(chuàng)建類 def __init__(self,threadname): # 初始化方法 # 調(diào)用父類的初始化方法 threading.Thread.__init__(self,name = threadname) def run(self): # 重載run方法 global x # 使用global表明x為全局變量 for i in range(3): x = x + 1 time.sleep(5) # 調(diào)用sleep函數(shù),讓線程休眠5秒 print x tl = [] # 定義列表 for i in range(10): t = mythread(str(i)) # 類實例化 tl.append(t) # 將類對象添加到列表中 x=0 # 將x賦值為0 for i in tl: i.start()
這里執(zhí)行的結(jié)果和想想的不同,結(jié)果如下:
[root@361way lock]# python lock1.py
30 30 30 30 30 30 30 30 30 30
為什么結(jié)果都是30呢?關(guān)鍵在于global 行和 time.sleep行。
1、由于x是一個全局變量,所以每次循環(huán)后 x 的值都是執(zhí)行后的結(jié)果值;
2、由于該代碼是多線程的操作,所以在sleep 等待的時候,之前已經(jīng)執(zhí)行完成的線程會在這等待,而后續(xù)的進程在等待的5秒這段時間也執(zhí)行完成 ,等待print。同樣由于global 的原理,x被重新斌值。所以打印出的結(jié)果全是30 ;
3、便于理解,可以嘗試將sleep等注釋,你再看下結(jié)果,就會發(fā)現(xiàn)有不同。
在實際應用中,如抓取程序等,也會出現(xiàn)類似于sleep等待的情況。在前后調(diào)用有順序或打印有輸出的時候,就會現(xiàn)并發(fā)競爭,造成結(jié)果或輸出紊亂。這里就引入了鎖的概念,上面的代碼修改下,如下:
[root@361way lock]# cat lock2.py
#!/usr/bin/env python # coding=utf-8 import threading # 導入threading模塊 import time # 導入time模塊 class mythread(threading.Thread): # 通過繼承創(chuàng)建類 def __init__(self,threadname): # 初始化方法 threading.Thread.__init__(self,name = threadname) def run(self): # 重載run方法 global x # 使用global表明x為全局變量 lock.acquire() # 調(diào)用lock的acquire方法 for i in range(3): x = x + 1 time.sleep(5) # 調(diào)用sleep函數(shù),讓線程休眠5秒 print x lock.release() # 調(diào)用lock的release方法 lock = threading.Lock() # 類實例化 tl = [] # 定義列表 for i in range(10): t = mythread(str(i)) # 類實例化 tl.append(t) # 將類對象添加到列表中 x=0 # 將x賦值為0 for i in tl: i.start() # 依次運行線程
執(zhí)行的結(jié)果如下:
3 6 9 12 15 18 21 24 27 30
加鎖的結(jié)果會造成阻塞,而且會造成開鎖大。會根據(jù)順序由并發(fā)的多線程按順序輸出,如果后面的線程執(zhí)行過快,需要等待前面的進程結(jié)束后其才能結(jié)束 --- 寫的貌似有點像隊列的概念了 ,不過在加鎖的很多場景下確實可以通過隊列去解決。
以上就是怎么解鎖Python中的死鎖機制,小編相信有部分知識點可能是我們?nèi)粘9ぷ鲿姷交蛴玫降摹OM隳芡ㄟ^這篇文章學到更多知識。更多詳情敬請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。
新聞名稱:怎么解鎖Python中的死鎖機制
分享URL:http://vcdvsql.cn/article42/iiggec.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供ChatGPT、做網(wǎng)站、App開發(fā)、微信小程序、面包屑導航、微信公眾號
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)