Python多線程操作之互斥鎖、遞歸鎖、信號(hào)量、事件實(shí)例詳解
本文實(shí)例講述了Python多線程操作之互斥鎖、遞歸鎖、信號(hào)量、事件。分享給大家供大家參考,具體如下:
互斥鎖: 為什么要有互斥鎖:由于多線程是并行的,如果某一線程取出了某一個(gè)數(shù)據(jù)將要進(jìn)行操作,但它還沒有那么快執(zhí)行完操作,這時(shí)候如果另外一個(gè)線程也要操作這個(gè)數(shù)據(jù),那么這個(gè)數(shù)據(jù)可能會(huì)因?yàn)閮纱尾僮鞫l(fā)生錯(cuò)誤import time,threadingx=6def run1(): print('run1我拿到了數(shù)據(jù):',x) print('我現(xiàn)在還不想操作,先睡一下') time.sleep(3) print('再看一下數(shù)據(jù),穩(wěn)一穩(wěn)',x)def run2(): global x print('run2我拿到了數(shù)據(jù):', x) x=5 print(x)t1=threading.Thread(target=run1)t2=threading.Thread(target=run2)t1.start()t2.start()t1.join()t2.join()
使用互斥鎖來更改上段代碼
import time,threadingx=6def run1(): lock.acquire() global x print('run1我拿到了數(shù)據(jù),x=',x) print('我現(xiàn)在還不想操作,先睡一下') time.sleep(3) print('再看一下數(shù)據(jù),穩(wěn)一穩(wěn),x=',x) x+=1 print('run1操作完畢:x=',x) lock.release()def run2(): lock.acquire() global x print('run2我拿到了數(shù)據(jù):', x) x+=1 print('run2操作完畢:x=',x) lock.release()lock=threading.Lock()#生成一個(gè)鎖對象t1=threading.Thread(target=run1)t2=threading.Thread(target=run2)t1.start()t2.start()start_time=time.time()t1.join()t2.join()print('最終的x=',x)print(time.time()-start_time)#3.0多說明,由于受到鎖的影響,run2要等待run1釋放lock,所以變成了串行
這種互斥鎖在操作系統(tǒng)中可以稱作“臨界區(qū)”,如果想了解更多:
https://baike.baidu.com/item/%E4%B8%B4%E7%95%8C%E5%8C%BA/8942134?fr=aladdin
【以過獨(dú)木橋?yàn)槔浚簶蛑荒苋菀粋€(gè)人通過,A只能看得到北邊橋上有沒有人,看不到南邊橋有沒有人,當(dāng)他看到北邊橋沒人就會(huì)過橋,等到他到橋中間才能看到南邊橋有沒有人,B情況相反:【于是當(dāng)兩個(gè)人一起過橋的時(shí)候就會(huì)發(fā)生死鎖】
import threading,time'''A只能看得到北邊橋上有沒有人,看不到南邊橋有沒有人,當(dāng)他看到北邊橋沒人就會(huì)過橋,等到他到橋中間才能看到南邊橋有沒有人'''def A(): lockNorth.acquire()#拿到北邊橋的鎖 print('A過橋北') time.sleep(3)#過橋中 lockSorth.acquire()#企圖過到南邊橋, print('A過橋南') time.sleep(3) # 過橋中 lockSorth.release() lockNorth.release() print('A過橋成功')'''B只能看得到南邊橋上有沒有人,看不到北邊橋有沒有人,當(dāng)他看到南邊橋沒人就會(huì)過橋,等到他到橋中間才能看到北邊橋有沒有人'''def B(): lockSorth.acquire() # 企圖過到南邊橋, print('B過橋南') time.sleep(3) # 過橋中 lockNorth.acquire() # 拿到北邊橋的鎖 print('B過橋北') time.sleep(3) # 過橋中 lockNorth.release() lockSorth.release() print('B過橋成功')lockNorth=threading.Lock()lockSorth=threading.Lock()tA=threading.Thread(target=A)tB=threading.Thread(target=B)tA.start()tB.start()tA.join()tB.join()
使用遞歸鎖來解決上面的死鎖問題:
import threading,time'''A只能看得到北邊橋上有沒有人,看不到南邊橋有沒有人,當(dāng)他看到北邊橋沒人就會(huì)過橋,等到他到橋中間才能看到南邊橋有沒有人'''def A(): lock.acquire()#拿到北邊橋的鎖 print('A過橋北') time.sleep(3)#過橋中 lock.acquire()#企圖過到南邊橋, print('A過橋南') time.sleep(3) # 過橋中 lock.release() lock.release() print('A過橋成功')'''B只能看得到南邊橋上有沒有人,看不到北邊橋有沒有人,當(dāng)他看到南邊橋沒人就會(huì)過橋,等到他到橋中間才能看到北邊橋有沒有人'''def B(): lock.acquire() # 拿南橋鎖, print('B過橋南') time.sleep(3) # 過橋中 lock.acquire() # 企圖拿北橋的鎖 print('B過橋北') time.sleep(3) # 過橋中 lock.release() lock.release() print('B過橋成功')lock=threading.RLock()tA=threading.Thread(target=A)tB=threading.Thread(target=B)tA.start()tB.start()tA.join()tB.join()
【由于本質(zhì)是一把鎖,A拿到鎖后,B要等待】
信號(hào)量: 什么是信號(hào)量:信號(hào)量可以限制進(jìn)入的線程的數(shù)量。
如何使用信號(hào)量: 創(chuàng)建信號(hào)量對象:信號(hào)量對象=threading.BoundedSemaphore(x),x是限制進(jìn)程的數(shù)量 當(dāng)有進(jìn)程需要進(jìn)入的時(shí)候,調(diào)用acquire()來減少信號(hào)量:信號(hào)量對象.acquire() 當(dāng)有進(jìn)程離開的時(shí)候,調(diào)用release()來增加信號(hào)量:信號(hào)量對象.release()import threading,timedef run(): s.acquire() print('hello') time.sleep(1.5) s.release()s=threading.BoundedSemaphore(3)#限制3個(gè)threading_list=[]for i in range(12):#創(chuàng)建12個(gè)線程 obj=threading.Thread(target=run) obj.setDaemon(True) # 設(shè)置守護(hù)線程,避免干擾主線程運(yùn)行,并行等待 obj.start()for i in range(4): print('')#為了把結(jié)果分割,可以清楚看出分為了三組 time.sleep(1.5)#結(jié)果分為三組是因?yàn)檫\(yùn)行的太快了,三個(gè)線程裝入的時(shí)間差太小
import threading,timedef read(): while True: if event.is_set(): print('事件已設(shè)置,我要讀了!!!!') time.sleep(1) else:#事件未設(shè)置 print('還沒寫好,我要等咯') event.wait()#那么就等著咯 #如果等到了 print('終于等到了!那么我又可以讀了') time.sleep(1)def write(): event.clear()#初始設(shè)空 while True: time.sleep(3)#寫 event.set()#設(shè)置事件,一旦set,那么讀者wait就有返回了,讀者可以繼續(xù)運(yùn)行了 print('write:寫好了') time.sleep(2)#等人讀 event.clear()#清除事件event=threading.Event() #創(chuàng)建事件對象t1=threading.Thread(target=write)t2=threading.Thread(target=read)t1.start()t2.start()t1.join()t2.join()'''結(jié)果顯示:讀者確實(shí)一直在等待寫者寫好'''
更多關(guān)于Python相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Python進(jìn)程與線程操作技巧總結(jié)》、《Python數(shù)據(jù)結(jié)構(gòu)與算法教程》、《Python函數(shù)使用技巧總結(jié)》、《Python字符串操作技巧匯總》、《Python入門與進(jìn)階經(jīng)典教程》、《Python+MySQL數(shù)據(jù)庫程序設(shè)計(jì)入門教程》及《Python常見數(shù)據(jù)庫操作技巧匯總》
希望本文所述對大家Python程序設(shè)計(jì)有所幫助。
相關(guān)文章:
1. css代碼優(yōu)化的12個(gè)技巧2. .NET SkiaSharp 生成二維碼驗(yàn)證碼及指定區(qū)域截取方法實(shí)現(xiàn)3. django創(chuàng)建css文件夾的具體方法4. ASP中if語句、select 、while循環(huán)的使用方法5. ASP中實(shí)現(xiàn)字符部位類似.NET里String對象的PadLeft和PadRight函數(shù)6. jsp網(wǎng)頁實(shí)現(xiàn)貪吃蛇小游戲7. ASP 信息提示函數(shù)并作返回或者轉(zhuǎn)向8. 存儲(chǔ)于xml中需要的HTML轉(zhuǎn)義代碼9. MyBatis JdbcType 與Oracle、MySql數(shù)據(jù)類型對應(yīng)關(guān)系說明10. CentOS郵件服務(wù)器搭建系列—— POP / IMAP 服務(wù)器的構(gòu)建( Dovecot )
