日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > python >内容正文

python

11.python并发入门(part4 死锁与递归锁)

發(fā)布時(shí)間:2025/3/21 python 57 豆豆
生活随笔 收集整理的這篇文章主要介紹了 11.python并发入门(part4 死锁与递归锁) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、關(guān)于死鎖。

死鎖,就是當(dāng)多個(gè)進(jìn)程或者線程在執(zhí)行的過程中,因爭奪共享資源而造成的一種互相等待的現(xiàn)象,一旦產(chǎn)生了死鎖,不加人工處理,程序會(huì)一直等待下去,這也被稱為死鎖進(jìn)程。

下面是一個(gè)產(chǎn)生“死鎖”現(xiàn)象的例子:

import threading

import time

lock_a = threading.Lock()

lock_b = threading.Lock()

class test_thread(threading.Thread):

? ? def __init__(self):

? ? ? ? super(test_thread,self).__init__()

? ? def run(self):

? ? ? ? self.fun1()

? ? ? ? self.fun2()

? ? def fun1(self):

? ? ? ? lock_a.acquire()

? ? ? ? print "I am %s , get res: %s---%s" %(self.name, "ResA",time.time())

? ? ? ? lock_b.acquire()

? ? ? ? print "I am %s , get res: %s---%s" %(self.name, "ResB",time.time())

? ? ? ? lock_b.release()

? ? ? ? lock_a.release()

? ? def fun2(self):

? ? ? ? lock_b.acquire()

? ? ? ? print ("I am %s , get res: %s---%s" %(self.name, "ResB",time.time()))

? ? ? ? time.sleep(0.2)

? ? ? ? lock_a.acquire()

? ? ? ? print ("I am %s , get res: %s---%s" %(self.name, "ResA",time.time()))

? ? ? ? lock_a.release()

? ? ? ? lock_b.release()

if __name__ == "__main__":

? ? print "start---------------------------%s"%(time.time())

? ? for i in range(0, 10):

? ? ? ? my_thread = test_thread()

? ? ? ? my_thread.start()


輸出執(zhí)行結(jié)果:

start---------------------------1494682814.1

I am Thread-1 , get res: ResA---1494682814.1

I am Thread-1 , get res: ResB---1494682814.1

I am Thread-1 , get res: ResB---1494682814.1

I am Thread-2 , get res: ResA---1494682814.1


下面來分析代碼,為什么會(huì)產(chǎn)生死鎖:

開了10個(gè)線程,首先肯定會(huì)有一個(gè)線程去拿到lock_a這把鎖,其余的線程只能阻塞,一直等到lock_a這把鎖被釋放,然后這個(gè)線程又獲得了一把鎖就是lock_b,執(zhí)行完了一條print操作后,釋放lock_b這把鎖,此時(shí),其他的線程還是沒有辦法去執(zhí)行func1里面的資源,釋放了lock_b這把鎖后,緊接著lock_a也被釋放了,此時(shí),下一個(gè)線程就可以去執(zhí)行func1中的資源了,接下來,線程1執(zhí)行到了func2拿到了lock_b這把鎖,然后執(zhí)行一個(gè)print輸出,I am Thread-1 , get res: ResB---1494682814.1,sleep0.2秒,在第一個(gè)線程sleep的過程中第二個(gè)線程開始執(zhí)行,第二個(gè)線程在執(zhí)行func1的時(shí)候,首先拿到了lock_a這把鎖,執(zhí)行了下面的print語句,I am Thread-2 , get res: ResA---1494682814.1,此時(shí)的情況就是線程1拿到了lock_b這把鎖,線程2拿到了lock_a這把鎖,那么問題來了,線程2如果想繼續(xù)執(zhí)行func1后面的內(nèi)容,需要去獲得lock_b這把鎖,而此時(shí)lock_b鎖已經(jīng)被線程1拿走了(線程1執(zhí)行到了func2拿走了lock_b鎖,并且還沒被釋放~),線程1,sleep0.2秒后,需要繼續(xù)執(zhí)行func2中的內(nèi)容,此時(shí),需要拿到lock_a鎖,(lock_a鎖,被線程2執(zhí)行func1的時(shí)候拿走了,并且沒有被釋放~),現(xiàn)在的情況就是線程1需要lock_a鎖,但是lock_a在線程2手里,線程2需要lock_b鎖,但是lock_b鎖在線程1手里~雙方都沒有辦法執(zhí)行到后面的釋放操作。

這也就相當(dāng)于兩個(gè)人要做交易,甲手里有蘋果乙手里有菠蘿,甲想吃乙手里的菠蘿,乙想吃甲手里的蘋果,但是誰都不愿意先把自己手里的東西先給對(duì)方~所以程序就會(huì)一直卡在這。

這就是死鎖形成的原理。


二、遞歸鎖。

解決死鎖問題有一個(gè)特別有效的方法,就是遞歸鎖.

遞歸鎖與普通的互斥鎖最大的不同就是,一個(gè)鎖的對(duì)象內(nèi)部,維護(hù)了一個(gè)計(jì)數(shù)器,這個(gè)計(jì)數(shù)器的初始值是0,當(dāng)一個(gè)線程acquire一次這個(gè)鎖時(shí),內(nèi)部計(jì)數(shù)器+1,但是,這把鎖的計(jì)數(shù)器一旦大于0,其他的線程是無法拿到這把鎖的,只有當(dāng)前線程可以拿。

(當(dāng)前線程acquire一次,計(jì)數(shù)器+1,release一次計(jì)數(shù)器-1,所以,當(dāng)前的線程想要徹底釋放掉遞歸鎖,acquire多少次,就要release多少次!!!)

(這個(gè)計(jì)數(shù)器,就是遞歸鎖中的count。)


還拿剛才的那段產(chǎn)生死鎖的代碼來舉例:

import threading

import time

r_lock = threading.RLock() #RLock是用來產(chǎn)生遞歸鎖的一個(gè)類,產(chǎn)生一個(gè)遞歸鎖。

class test_thread(threading.Thread):

? ? def __init__(self):

? ? ? ? super(test_thread,self).__init__()

? ? def run(self):

? ? ? ? self.fun1()

? ? ? ? self.fun2()

? ? def fun1(self):

? ? ? ? r_lock.acquire() #count+1

? ? ? ? print "I am %s , get res: %s---%s" %(self.name, "ResA",time.time())

? ? ? ? r_lock.acquire() #count再+1

? ? ? ? print "I am %s , get res: %s---%s" %(self.name, "ResB",time.time())

? ? ? ? r_lock.release() #count -1

? ? ? ? r_lock.release() #count 再-1

? ? def fun2(self):

? ? ? ? r_lock.acquire()

? ? ? ? print ("I am %s , get res: %s---%s" %(self.name, "ResB",time.time()))

? ? ? ? time.sleep(0.2)

? ? ? ? r_lock.acquire()

? ? ? ? print ("I am %s , get res: %s---%s" %(self.name, "ResA",time.time()))

? ? ? ? r_lock.release()

? ? ? ? r_lock.release()

if __name__ == "__main__":

? ? print "start---------------------------%s"%(time.time())

? ? r_lock = threading.RLock()

? ? for i in range(0, 10):

? ? ? ? my_thread = test_thread()

? ? ? ? my_thread.start()


輸出結(jié)果:

start---------------------------1494687542.43

I am Thread-1 , get res: ResA---1494687542.43

I am Thread-1 , get res: ResB---1494687542.43

I am Thread-1 , get res: ResB---1494687542.43

I am Thread-1 , get res: ResA---1494687542.63

I am Thread-2 , get res: ResA---1494687542.63

I am Thread-2 , get res: ResB---1494687542.63

I am Thread-2 , get res: ResB---1494687542.63

I am Thread-2 , get res: ResA---1494687542.83

I am Thread-4 , get res: ResA---1494687542.83

I am Thread-4 , get res: ResB---1494687542.83

I am Thread-4 , get res: ResB---1494687542.83

I am Thread-4 , get res: ResA---1494687543.04

I am Thread-6 , get res: ResA---1494687543.04

I am Thread-6 , get res: ResB---1494687543.04

I am Thread-6 , get res: ResB---1494687543.04

I am Thread-6 , get res: ResA---1494687543.24

I am Thread-8 , get res: ResA---1494687543.24

I am Thread-8 , get res: ResB---1494687543.24

I am Thread-8 , get res: ResB---1494687543.24

I am Thread-8 , get res: ResA---1494687543.44

I am Thread-10 , get res: ResA---1494687543.44

I am Thread-10 , get res: ResB---1494687543.44

I am Thread-10 , get res: ResB---1494687543.44

I am Thread-10 , get res: ResA---1494687543.65

I am Thread-5 , get res: ResA---1494687543.65

I am Thread-5 , get res: ResB---1494687543.65

I am Thread-5 , get res: ResB---1494687543.65

I am Thread-5 , get res: ResA---1494687543.85

I am Thread-9 , get res: ResA---1494687543.85

I am Thread-9 , get res: ResB---1494687543.85

I am Thread-9 , get res: ResB---1494687543.85

I am Thread-9 , get res: ResA---1494687544.06

I am Thread-7 , get res: ResA---1494687544.06

I am Thread-7 , get res: ResB---1494687544.06

I am Thread-7 , get res: ResB---1494687544.06

I am Thread-7 , get res: ResA---1494687544.26

I am Thread-3 , get res: ResA---1494687544.26

I am Thread-3 , get res: ResB---1494687544.26

I am Thread-3 , get res: ResB---1494687544.26

I am Thread-3 , get res: ResA---1494687544.46


從上面的例子來看,死鎖的問題被完美的解決掉了。

最后,總結(jié)下遞歸鎖:

在python中,如果同一個(gè)線程需要多次去訪問同一個(gè)共享資源,這個(gè)時(shí)候,就可以使用遞歸鎖(RLock),遞歸鎖的內(nèi)部,維護(hù)了一個(gè)Lock對(duì)象和一個(gè)counter計(jì)數(shù)變量,counter記錄了acquire的次數(shù),從而使得資源可以被多次require。直到一個(gè)線程所有的acquire都被release,其他的線程才能獲得資源。

所以說RLock可以完全代替Lock,能用遞歸鎖盡量用遞歸鎖!




? ? ? 本文轉(zhuǎn)自蘇浩智 51CTO博客,原文鏈接:http://blog.51cto.com/suhaozhi/1925393,如需轉(zhuǎn)載請(qǐng)自行聯(lián)系原作者




總結(jié)

以上是生活随笔為你收集整理的11.python并发入门(part4 死锁与递归锁)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。