python多线程之线程锁(Lock)和递归锁(RLock)实例
?
?
一、線程鎖
Threading模塊為我們提供了一個(gè)類,Threading.Lock鎖。我們創(chuàng)建一個(gè)該類對(duì)象,在線程函數(shù)執(zhí)行前,“搶占”該鎖,執(zhí)行完成后,“釋放”該鎖,則我們確保了每次只有一個(gè)線程占有該鎖。這時(shí)候?qū)σ粋€(gè)公共的對(duì)象進(jìn)行操作,則不會(huì)發(fā)生線程不安全的現(xiàn)象了。
1、我們先建立了一個(gè)threading.Lock類對(duì)象lock,在run方法里,我們使用lock.acquire()獲得了這個(gè)鎖。此時(shí),其他的線程就無(wú)法再獲得該鎖了,他們就會(huì)阻塞在“if lock.acquire()”這里,直到鎖被另一個(gè)線程釋放:lock.release()。
2、如果多個(gè)線程要調(diào)用多個(gè)現(xiàn)象,而A線程調(diào)用A鎖占用了A對(duì)象,B線程調(diào)用了B鎖占用了B對(duì)象,A線程不能調(diào)用B對(duì)象,B線程不能調(diào)用A對(duì)象,于是一直等待。這就造成了線程“死鎖”。
Threading模塊中,也有一個(gè)類,RLock,稱之為可重入鎖。該鎖對(duì)象內(nèi)部維護(hù)著一個(gè)Lock和一個(gè)counter對(duì)象。counter對(duì)象記錄了acquire的次數(shù),使得資源可以被多次require。最后,當(dāng)所有RLock被release后,其他線程才能獲取資源。在同一個(gè)線程中,RLock.acquire可以被多次調(diào)用,利用該特性,可以解決部分死鎖問(wèn)題
3、當(dāng)多個(gè)線程同時(shí)訪問(wèn)一個(gè)數(shù)據(jù)時(shí),需加鎖,排隊(duì)變成單線程一個(gè)一個(gè)執(zhí)行
4、加鎖避免并發(fā)導(dǎo)致邏輯出錯(cuò)
5、每當(dāng)一個(gè)線程a要訪問(wèn)共享數(shù)據(jù)時(shí),必須先獲得鎖定;如果已經(jīng)有別的線程b獲得鎖定了,那么就讓線程a暫停,也就是同步阻塞;等到線程b訪問(wèn)完畢,釋放鎖以后,再讓線程a繼續(xù)
6、語(yǔ)法
lock=threading.Lock() #創(chuàng)建線程鎖
lock = threading.RLock()#創(chuàng)建遞歸鎖(多個(gè)鎖時(shí)用這個(gè))
lock.acquire() #鎖住
lock.release() 釋放鎖
?
二、線程鎖實(shí)例
#未加鎖 如果多個(gè)線程同時(shí)操作某個(gè)數(shù)據(jù),會(huì)出現(xiàn)不可預(yù)料的結(jié)果。比如以下場(chǎng)景:當(dāng)小伙伴a在往火鍋里面添加魚(yú)丸的時(shí)候,小伙伴b在同時(shí)吃掉魚(yú)丸,這很有可能導(dǎo)致剛下鍋的魚(yú)丸被夾出來(lái)了(沒(méi)有熟),或者還沒(méi)下鍋,就去夾魚(yú)丸(夾不到)# coding=utf-8 import threading import time def chiHuoGuo(people, do):print("%s 吃火鍋的小伙伴:%s" % (time.ctime(),people))time.sleep(1)for i in range(3):time.sleep(1)print("%s %s正在 %s 魚(yú)丸"% (time.ctime(), people, do))print("%s 吃火鍋的小伙伴:%s" % (time.ctime(),people)) class myThread (threading.Thread): # 繼承父類threading.Threaddef __init__(self, people, name, do):'''重寫(xiě)threading.Thread初始化內(nèi)容'''threading.Thread.__init__(self)self.threadName = nameself.people = peopleself.do = dodef run(self): # 把要執(zhí)行的代碼寫(xiě)到run函數(shù)里面 線程在創(chuàng)建后會(huì)直接運(yùn)行run函數(shù)'''重寫(xiě)run方法'''print("開(kāi)始線程: " + self.threadName)chiHuoGuo(self.people, self.do) # 執(zhí)行任務(wù)print("結(jié)束線程: " + self.name) print("yoyo請(qǐng)小伙伴開(kāi)始吃火鍋:!!!") # 設(shè)置線程組 threads = [] # 創(chuàng)建新線程 thread1 = myThread("xiaoming", "Thread-1", "添加") thread2 = myThread("xiaowang", "Thread-2", "吃掉") # 添加到線程組 threads.append(thread1) threads.append(thread2) # 開(kāi)啟線程 for thread in threads:thread.start() # 阻塞主線程,等子線程結(jié)束 for thread in threads:thread.join() time.sleep(0.1) print("退出主線程:吃火鍋結(jié)束,結(jié)賬走人")C:\Users\wangli\PycharmProjects\AutoMation\venv\Scripts\python.exe C:/Users/wangli/PycharmProjects/AutoMation/case/test.py yoyo請(qǐng)小伙伴開(kāi)始吃火鍋:!!! 開(kāi)始線程: Thread-1 Fri Mar 15 08:33:19 2019 吃火鍋的小伙伴:xiaoming 開(kāi)始線程: Thread-2 Fri Mar 15 08:33:19 2019 吃火鍋的小伙伴:xiaowang Fri Mar 15 08:33:21 2019 xiaowang正在 吃掉 魚(yú)丸 Fri Mar 15 08:33:21 2019 xiaoming正在 添加 魚(yú)丸 Fri Mar 15 08:33:22 2019 xiaowang正在 吃掉 魚(yú)丸 Fri Mar 15 08:33:22 2019 xiaoming正在 添加 魚(yú)丸 Fri Mar 15 08:33:23 2019 xiaowang正在 吃掉 魚(yú)丸 Fri Mar 15 08:33:23 2019 吃火鍋的小伙伴:xiaowang 結(jié)束線程: Thread-2 Fri Mar 15 08:33:23 2019 xiaoming正在 添加 魚(yú)丸 Fri Mar 15 08:33:23 2019 吃火鍋的小伙伴:xiaoming 結(jié)束線程: Thread-1 退出主線程:吃火鍋結(jié)束,結(jié)賬走人Process finished with exit code 0 #線程鎖,單鎖實(shí)例 import time,threading def run(n):lock.acquire() #加鎖global numnum+=1lock.release() #釋放鎖 lock=threading.Lock()#獲得線程鎖 num=0 threads=[] for i in range(50):thread=threading.Thread(target=run,args=("t-%s"%i,))thread.start()threads.append(thread) for i in threads:i.join() print("num:",num)C:\Users\wangli\PycharmProjects\AutoMation\venv\Scripts\python.exe C:/Users/wangli/PycharmProjects/AutoMation/case/test.py num: 50Process finished with exit code 0 #線程鎖,加鎖實(shí)例# coding=utf-8 import threading import time def chiHuoGuo(people, do):print("%s 吃火鍋的小伙伴:%s" % (time.ctime(),people))time.sleep(1)for i in range(3):time.sleep(1)print("%s %s正在 %s 魚(yú)丸"% (time.ctime(), people, do))print("%s 吃火鍋的小伙伴:%s" % (time.ctime(),people)) class myThread (threading.Thread): # 繼承父類threading.Threadlock = threading.Lock() # 線程鎖def __init__(self, people, name, do):'''重寫(xiě)threading.Thread初始化內(nèi)容'''threading.Thread.__init__(self)self.threadName = nameself.people = peopleself.do = dodef run(self): # 把要執(zhí)行的代碼寫(xiě)到run函數(shù)里面 線程在創(chuàng)建后會(huì)直接運(yùn)行run函數(shù)'''重寫(xiě)run方法'''print("開(kāi)始線程: " + self.threadName)# 執(zhí)行任務(wù)之前鎖定線程self.lock.acquire()chiHuoGuo(self.people, self.do) # 執(zhí)行任務(wù)# 執(zhí)行完之后,釋放鎖self.lock.release()print("結(jié)束線程: " + self.name) print("yoyo請(qǐng)小伙伴開(kāi)始吃火鍋:!!!") # 設(shè)置線程組 threads = [] # 創(chuàng)建新線程 thread1 = myThread("xiaoming", "Thread-1", "添加") thread2 = myThread("xiaowang", "Thread-2", "吃掉") # 添加到線程組 threads.append(thread1) threads.append(thread2) # 開(kāi)啟線程 for thread in threads:thread.start() # 阻塞主線程,等子線程結(jié)束 for thread in threads:thread.join() time.sleep(0.1) print("退出主線程:吃火鍋結(jié)束,結(jié)賬走人")C:\Users\wangli\PycharmProjects\AutoMation\venv\Scripts\python.exe C:/Users/wangli/PycharmProjects/AutoMation/case/test.py yoyo請(qǐng)小伙伴開(kāi)始吃火鍋:!!! 開(kāi)始線程: Thread-1 Fri Mar 15 08:36:39 2019 吃火鍋的小伙伴:xiaoming 開(kāi)始線程: Thread-2 Fri Mar 15 08:36:41 2019 xiaoming正在 添加 魚(yú)丸 Fri Mar 15 08:36:42 2019 xiaoming正在 添加 魚(yú)丸 Fri Mar 15 08:36:43 2019 xiaoming正在 添加 魚(yú)丸 Fri Mar 15 08:36:43 2019 吃火鍋的小伙伴:xiaoming 結(jié)束線程: Thread-1 Fri Mar 15 08:36:43 2019 吃火鍋的小伙伴:xiaowang Fri Mar 15 08:36:45 2019 xiaowang正在 吃掉 魚(yú)丸 Fri Mar 15 08:36:47 2019 xiaowang正在 吃掉 魚(yú)丸 Fri Mar 15 08:36:48 2019 xiaowang正在 吃掉 魚(yú)丸 Fri Mar 15 08:36:48 2019 吃火鍋的小伙伴:xiaowang 結(jié)束線程: Thread-2 退出主線程:吃火鍋結(jié)束,結(jié)賬走人Process finished with exit code 0 #線程鎖,多個(gè)鎖時(shí),需加遞歸鎖import threading, time def run1():print("grab the first part data")lock.acquire()global numnum += 1lock.release()return num def run2():print("grab the second part data")lock.acquire()global num2num2 += 1lock.release()return num2 def run3():lock.acquire()res = run1()print('--------between run1 and run2-----')res2 = run2()lock.release()print(res, res2) num, num2 = 0, 0 lock = threading.RLock() #遞歸鎖 for i in range(3):t = threading.Thread(target=run3)t.start() while threading.active_count() != 1:print(threading.active_count()) else:print('----all threads done---')print(num, num2)?
總結(jié)
以上是生活随笔為你收集整理的python多线程之线程锁(Lock)和递归锁(RLock)实例的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【Python爬虫】Windows环境下
- 下一篇: 分享几个接口自动化的实战练手项目