python多線程互斥鎖與死鎖問題詳解
一、多線程共享全局變量
代碼實(shí)現(xiàn)的功能:
創(chuàng)建work01與worker02函數(shù),對全局變量進(jìn)行加一操作創(chuàng)建main函數(shù),生成兩個線程,同時調(diào)用兩個函數(shù)
代碼如下:
import threading result = 0 # 定義全局變量result def work1(num): global result for i in range(num): result += 1 print('------from work1-------', result) def work2(num): global result for i in range(num): result += 1 print('------from work2-------', result) def main(): print('--------begin--------', result) # 創(chuàng)建兩個線程 t1 = threading.Thread(target=work1, args=(1000,)) t2 = threading.Thread(target=work1, args=(1000,)) t1.start() t2.start() if __name__ == '__main__': main()
運(yùn)行結(jié)果:
--------begin---------- 0 ------from work1------- 1000 ------from work1------- 2000
兩個線程之間共享了全局變量result,但是當(dāng)我們把range的數(shù)值調(diào)大一些,
t1 = threading.Thread(target=work1, args=(1000000,)) t2 = threading.Thread(target=work1, args=(1000000,))
我們再來看一下結(jié)果,這是為什么呢,我們往下看一下結(jié)果:
--------begin---------- 0 ------from work1------- 1358452 ------from work1------- 1696352
總結(jié):
在一個進(jìn)程內(nèi)的所有線程共享全局變量,很方便在多個線程間共享數(shù)據(jù)
缺點(diǎn)就是,線程是對全局變量隨意遂改可能造成多線程之間對全局變量的混亂(即線程非安全)
二、給線程加一把鎖鎖
假如當(dāng)前 g_num 值是100,當(dāng)線程1執(zhí)行第一步時,cpu通過計(jì)算獲得結(jié)果101,并準(zhǔn)備把計(jì)算的結(jié)果101賦值給g_num,然后再傳值的過程中,線程2突然開始執(zhí)行了并且執(zhí)行了第一步,此時g_num的值仍未100,101還在傳遞的過程中,還沒成功賦值,線程2獲得計(jì)算結(jié)果101,并準(zhǔn)備傳遞給g_num,經(jīng)過一來一去這么一折騰,分明做了兩次加 1 操作,g_num結(jié)果卻是101,誤差就由此產(chǎn)生,往往循環(huán)次數(shù)越多,產(chǎn)生的誤差就越大,此時我們可以加一把鎖。
acquire() — 鎖定資源,此時資源是鎖定狀態(tài),其他線程無法修改鎖定的資源,直到等待鎖定的資源釋放之后才能操作;
release() — 釋放資源,也稱為解鎖操作,對鎖定的資源解鎖,解鎖之后其他線程可以對資源正常操作;
以上面的代碼為列子:想得到正確的結(jié)果,可以直接利用互斥鎖在全局變量 加1 之前 鎖定資源,然后在計(jì)算完成之后釋放資源,這樣就是一個完整的計(jì)算過程,至于應(yīng)該是哪個線程先執(zhí)行,無所謂,先到先得,憑本事說話….演示代碼如下:
# 開發(fā)時間:2022-01-27 12:59 import threading result = 0 # 定義全局變量result mutex = threading.Lock() def work1(num): global result mutex.acquire() for i in range(num): result += 1 print('------from work1-------', result) mutex.release() def work2(num): global result mutex.acquire() for i in range(num): result += 1 print('------from work2-------', result) mutex.release() def main(): print('--------begin----------', result) # 創(chuàng)建兩個線程 t1 = threading.Thread(target=work1, args=(100000000,)) t2 = threading.Thread(target=work1, args=(100000000,)) t1.start() t2.start() if __name__ == '__main__': main()
我們來看一下結(jié)果:
--------begin---------- 0 ------from work1------- 100000000 ------from work1------- 200000000
三、死鎖問題
1.單個互斥鎖的死鎖:
acquire()/release() 是成對出現(xiàn)的,互斥鎖對資源鎖定之后就一定要解鎖,否則資源會一直處于鎖定狀態(tài),其他線程無法修改;就好比上面的代碼,任何一個線程沒有釋放資源release(),程序就會一直處于阻塞狀態(tài)(在等待資源被釋放),不信你可以試一試~
2.多個互斥鎖的死鎖:
在同時操作多個互斥鎖的時候一定要格外小心,因?yàn)橐徊恍⌒木腿菀走M(jìn)入死循環(huán),假如有這樣一個場景:boss讓程序員一實(shí)現(xiàn)功能一的開發(fā),讓程序員二實(shí)現(xiàn)功能二的開發(fā),功能開發(fā)完成之后一起整合代碼!
# 導(dǎo)入線程threading模塊 import threading # 導(dǎo)入線程time模塊 import time # 創(chuàng)建互斥鎖 mutex_one = threading.Lock() mutex_two = threading.Lock() def programmer_thread1(): mutex_one.acquire() print("我是程序員1,module1開發(fā)正式開始,程序一加鎖,程序二加鎖") time.sleep(2) # 此時會堵塞,因?yàn)檫@個mutex_two已經(jīng)被線程programmer_thread2搶先上鎖了,等待解鎖 mutex_two.acquire() print("等待程序員2通知我合并代碼") mutex_two.release() print('程序員2開發(fā)完了,程序員1釋放第二把鎖') mutex_one.release() print('程序員1開發(fā)完了,程序員1釋放第一把鎖') def programmer_thread2(): mutex_two.acquire() print("我是程序員2,module2開發(fā)正式開始,程序二加鎖,程序一加鎖") time.sleep(2) # 此時會堵塞,因?yàn)檫@個mutex_one已經(jīng)被線程programmer_thread1搶先上鎖了,等待解鎖 #mutex_two.release() mutex_one.acquire() print("等待程序員1通知我合并代碼") mutex_one.release() print('程序員2釋放第一把鎖') # mutex_two.release() print('程序員2釋放第二把鎖') def main(): t1 = threading.Thread(target=programmer_thread1) t2 = threading.Thread(target=programmer_thread2) # 啟動線程 t1.start() t2.start() # 阻塞函數(shù),等待線程結(jié)束 t1.join() t2.join() # 整合代碼結(jié)束 print("整合代碼結(jié)束 ") if __name__ == "__main__": main()
分析下上面代碼:程序員1在等程序員2通知,程序員2在等程序員1通知,兩個線程都陷入阻塞中,因?yàn)閮蓚€線程都在等待對方解鎖,這就是死鎖!所以在開發(fā)中對于死鎖的問題還是需要多多注意!
總結(jié)
到此這篇關(guān)于python多線程互斥鎖與死鎖問題詳解的文章就介紹到這了,更多相關(guān)python互斥鎖與死鎖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用Tensorflow?hub完成目標(biāo)檢測過程詳解
這篇文章主要為大家介紹了使用Tensorflow?hub完成目標(biāo)檢測過程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04python中if-elif-else語句實(shí)例用法講解
在本篇文章里小編給大家整理的是一篇關(guān)于python中if-elif-else語句的使用注意事項(xiàng),有需要的便宜么可以跟著參考下。2021-10-10Django中使用 Closure Table 儲存無限分級數(shù)據(jù)
對于數(shù)據(jù)量大的情況(比如用戶之間有邀請鏈,有點(diǎn)三級分銷的意思),就要用到 closure table 的結(jié)構(gòu)來進(jìn)行存儲。這篇文章主要介紹了Django中使用 Closure Table 儲存無限分級數(shù)據(jù),需要的朋友可以參考下2019-06-06用Anaconda安裝本地python包的方法及路徑問題(圖文)
這篇文章主要介紹了用Anaconda安裝本地python包的方法及路徑問題,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-07-07pytorch中的優(yōu)化器optimizer.param_groups用法
這篇文章主要介紹了pytorch中的優(yōu)化器optimizer.param_groups用法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-05-05python實(shí)現(xiàn)的分析并統(tǒng)計(jì)nginx日志數(shù)據(jù)功能示例
這篇文章主要介紹了python實(shí)現(xiàn)的分析并統(tǒng)計(jì)nginx日志數(shù)據(jù)功能,結(jié)合實(shí)例形式分析了Python針對nginx日志ip、訪問url、狀態(tài)等數(shù)據(jù)的相關(guān)讀取、解析操作技巧,需要的朋友可以參考下2019-12-12