
舉例講解Python中的死鎖、可重入鎖和互斥鎖
一、死鎖
簡單來說,死鎖是一個(gè)資源被多次調(diào)用,而多次調(diào)用方都未能釋放該資源就會(huì)造成死鎖,這里結(jié)合例子說明下兩種常見的死鎖情況。
1、迭代死鎖
該情況是一個(gè)線程“迭代”請求同一個(gè)資源,直接就會(huì)造成死鎖:
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í)行了 ,除此之外也可以通過可重入鎖解決,后面會(huì)提到。
2、互相調(diào)用死鎖
上例中的死鎖是在同一個(gè)def函數(shù)內(nèi)多次調(diào)用造成的,另一種情況是兩個(gè)函數(shù)中都會(huì)調(diào)用相同的資源,互相等待對方結(jié)束的情況。如果兩個(gè)線程分別占有一部分資源并且同時(shí)等待對方的資源,就會(huì)造成死鎖。
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()
這個(gè)死鎖的示例稍微有點(diǎn)復(fù)雜。具體可以理下。
二、可重入鎖
為了支持在同一線程中多次請求同一資源,python提供了“可重入鎖”:threading.RLock。RLock內(nèi)部維護(hù)著一個(gè)Lock和一個(gè)counter變量,counter記錄了acquire的次數(shù),從而使得資源可以被多次require。直到一個(gè)線程所有的acquire都被release,其他的線程才能獲得資源。這里以例1為例,如果使用RLock代替Lock,則不會(huì)發(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()
和上面那個(gè)例子的不同之處在于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 # 導(dǎo)入threading模塊
import time # 導(dǎo)入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)) # 類實(shí)例化
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是一個(gè)全局變量,所以每次循環(huán)后 x 的值都是執(zhí)行后的結(jié)果值;
2、由于該代碼是多線程的操作,所以在sleep 等待的時(shí)候,之前已經(jīng)執(zhí)行完成的線程會(huì)在這等待,而后續(xù)的進(jìn)程在等待的5秒這段時(shí)間也執(zhí)行完成 ,等待print。同樣由于global 的原理,x被重新斌值。所以打印出的結(jié)果全是30 ;
3、便于理解,可以嘗試將sleep等注釋,你再看下結(jié)果,就會(huì)發(fā)現(xiàn)有不同。
在實(shí)際應(yīng)用中,如抓取程序等,也會(huì)出現(xiàn)類似于sleep等待的情況。在前后調(diào)用有順序或打印有輸出的時(shí)候,就會(huì)現(xiàn)并發(fā)競爭,造成結(jié)果或輸出紊亂。這里就引入了鎖的概念,上面的代碼修改下,如下:
[root@361way lock]# cat lock2.py
#!/usr/bin/env python
# coding=utf-8
import threading # 導(dǎo)入threading模塊
import time # 導(dǎo)入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() # 類實(shí)例化
tl = [] # 定義列表
for i in range(10):
t = mythread(str(i)) # 類實(shí)例化
tl.append(t) # 將類對象添加到列表中
x=0 # 將x賦值為0
for i in tl:
i.start() # 依次運(yùn)行線程
執(zhí)行的結(jié)果如下:
[root@361way lock]# python lock2.py
3
6
9
12
15
18
21
24
27
30
加鎖的結(jié)果會(huì)造成阻塞,而且會(huì)造成開鎖大。會(huì)根據(jù)順序由并發(fā)的多線程按順序輸出,如果后面的線程執(zhí)行過快,需要等待前面的進(jìn)程結(jié)束后其才能結(jié)束 --- 寫的貌似有點(diǎn)像隊(duì)列的概念了 ,不過在加鎖的很多場景下確實(shí)可以通過隊(duì)列去解決。
數(shù)據(jù)分析咨詢請掃描二維碼
若不方便掃碼,搜微信號(hào):CDAshujufenxi
LSTM 模型輸入長度選擇技巧:提升序列建模效能的關(guān)鍵? 在循環(huán)神經(jīng)網(wǎng)絡(luò)(RNN)家族中,長短期記憶網(wǎng)絡(luò)(LSTM)憑借其解決長序列 ...
2025-07-11CDA 數(shù)據(jù)分析師報(bào)考條件詳解與準(zhǔn)備指南? ? 在數(shù)據(jù)驅(qū)動(dòng)決策的時(shí)代浪潮下,CDA 數(shù)據(jù)分析師認(rèn)證愈發(fā)受到矚目,成為眾多有志投身數(shù) ...
2025-07-11數(shù)據(jù)透視表中兩列相乘合計(jì)的實(shí)用指南? 在數(shù)據(jù)分析的日常工作中,數(shù)據(jù)透視表憑借其強(qiáng)大的數(shù)據(jù)匯總和分析功能,成為了 Excel 用戶 ...
2025-07-11尊敬的考生: 您好! 我們誠摯通知您,CDA Level I和 Level II考試大綱將于 2025年7月25日 實(shí)施重大更新。 此次更新旨在確保認(rèn) ...
2025-07-10BI 大數(shù)據(jù)分析師:連接數(shù)據(jù)與業(yè)務(wù)的價(jià)值轉(zhuǎn)化者? ? 在大數(shù)據(jù)與商業(yè)智能(Business Intelligence,簡稱 BI)深度融合的時(shí)代,BI ...
2025-07-10SQL 在預(yù)測分析中的應(yīng)用:從數(shù)據(jù)查詢到趨勢預(yù)判? ? 在數(shù)據(jù)驅(qū)動(dòng)決策的時(shí)代,預(yù)測分析作為挖掘數(shù)據(jù)潛在價(jià)值的核心手段,正被廣泛 ...
2025-07-10數(shù)據(jù)查詢結(jié)束后:分析師的收尾工作與價(jià)值深化? ? 在數(shù)據(jù)分析的全流程中,“query end”(查詢結(jié)束)并非工作的終點(diǎn),而是將數(shù) ...
2025-07-10CDA 數(shù)據(jù)分析師考試:從報(bào)考到取證的全攻略? 在數(shù)字經(jīng)濟(jì)蓬勃發(fā)展的今天,數(shù)據(jù)分析師已成為各行業(yè)爭搶的核心人才,而 CDA(Certi ...
2025-07-09【CDA干貨】單樣本趨勢性檢驗(yàn):捕捉數(shù)據(jù)背后的時(shí)間軌跡? 在數(shù)據(jù)分析的版圖中,單樣本趨勢性檢驗(yàn)如同一位耐心的偵探,專注于從單 ...
2025-07-09year_month數(shù)據(jù)類型:時(shí)間維度的精準(zhǔn)切片? ? 在數(shù)據(jù)的世界里,時(shí)間是最不可或缺的維度之一,而year_month數(shù)據(jù)類型就像一把精準(zhǔn) ...
2025-07-09CDA 備考干貨:Python 在數(shù)據(jù)分析中的核心應(yīng)用與實(shí)戰(zhàn)技巧? ? 在 CDA 數(shù)據(jù)分析師認(rèn)證考試中,Python 作為數(shù)據(jù)處理與分析的核心 ...
2025-07-08SPSS 中的 Mann-Kendall 檢驗(yàn):數(shù)據(jù)趨勢與突變分析的有力工具? ? ? 在數(shù)據(jù)分析的廣袤領(lǐng)域中,準(zhǔn)確捕捉數(shù)據(jù)的趨勢變化以及識(shí)別 ...
2025-07-08備戰(zhàn) CDA 數(shù)據(jù)分析師考試:需要多久?如何規(guī)劃? CDA(Certified Data Analyst)數(shù)據(jù)分析師認(rèn)證作為國內(nèi)權(quán)威的數(shù)據(jù)分析能力認(rèn)證 ...
2025-07-08LSTM 輸出不確定的成因、影響與應(yīng)對策略? 長短期記憶網(wǎng)絡(luò)(LSTM)作為循環(huán)神經(jīng)網(wǎng)絡(luò)(RNN)的一種變體,憑借獨(dú)特的門控機(jī)制,在 ...
2025-07-07統(tǒng)計(jì)學(xué)方法在市場調(diào)研數(shù)據(jù)中的深度應(yīng)用? 市場調(diào)研是企業(yè)洞察市場動(dòng)態(tài)、了解消費(fèi)者需求的重要途徑,而統(tǒng)計(jì)學(xué)方法則是市場調(diào)研數(shù) ...
2025-07-07CDA數(shù)據(jù)分析師證書考試全攻略? 在數(shù)字化浪潮席卷全球的當(dāng)下,數(shù)據(jù)已成為企業(yè)決策、行業(yè)發(fā)展的核心驅(qū)動(dòng)力,數(shù)據(jù)分析師也因此成為 ...
2025-07-07剖析 CDA 數(shù)據(jù)分析師考試題型:解鎖高效備考與答題策略? CDA(Certified Data Analyst)數(shù)據(jù)分析師考試作為衡量數(shù)據(jù)專業(yè)能力的 ...
2025-07-04SQL Server 字符串截取轉(zhuǎn)日期:解鎖數(shù)據(jù)處理的關(guān)鍵技能? 在數(shù)據(jù)處理與分析工作中,數(shù)據(jù)格式的規(guī)范性是保證后續(xù)分析準(zhǔn)確性的基礎(chǔ) ...
2025-07-04CDA 數(shù)據(jù)分析師視角:從數(shù)據(jù)迷霧中探尋商業(yè)真相? 在數(shù)字化浪潮席卷全球的今天,數(shù)據(jù)已成為企業(yè)決策的核心驅(qū)動(dòng)力,CDA(Certifie ...
2025-07-04CDA 數(shù)據(jù)分析師:開啟數(shù)據(jù)職業(yè)發(fā)展新征程? ? 在數(shù)據(jù)成為核心生產(chǎn)要素的今天,數(shù)據(jù)分析師的職業(yè)價(jià)值愈發(fā)凸顯。CDA(Certified D ...
2025-07-03