Python程序中的线程操作-锁
生活随笔
收集整理的這篇文章主要介紹了
Python程序中的线程操作-锁
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
目錄
- 一、同步鎖
- 1.1 多個線程搶占資源的情況
- 1.1.1 對公共數據的操作
- 1.2 同步鎖的引用
- 1.3 互斥鎖與join的區別
- 1.1 多個線程搶占資源的情況
- 二、死鎖與遞歸鎖
- 2.1 死鎖
- 2.2 遞歸鎖RLock
- 三、典型問題:科學家吃面
- 3.1 死鎖問題
- 3.2 遞歸鎖解決死鎖問題
一、同步鎖
1.1 多個線程搶占資源的情況
from threading import Thread import os,time def work():global ntemp=ntime.sleep(0.1)n=temp-1 if __name__ == '__main__':n=100l=[]for i in range(100):p=Thread(target=work)l.append(p)p.start()for p in l:p.join()print(n) #結果可能為991.1.1 對公共數據的操作
import threading R=threading.Lock() R.acquire() ''' 對公共數據的操作 ''' R.release()1.2 同步鎖的引用
from threading import Thread,Lock import os,time def work():global nlock.acquire()temp=ntime.sleep(0.1)n=temp-1lock.release() if __name__ == '__main__':lock=Lock()n=100l=[]for i in range(100):p=Thread(target=work)l.append(p)p.start()for p in l:p.join()print(n) #結果肯定為0,由原來的并發執行變成串行,犧牲了執行效率保證了數據安全1.3 互斥鎖與join的區別
#不加鎖:并發執行,速度快,數據不安全 from threading import current_thread,Thread,Lock import os,time def task():global nprint('%s is running' %current_thread().getName())temp=ntime.sleep(0.5)n=temp-1if __name__ == '__main__':n=100lock=Lock()threads=[]start_time=time.time()for i in range(100):t=Thread(target=task)threads.append(t)t.start()for t in threads:t.join()stop_time=time.time()print('主:%s n:%s' %(stop_time-start_time,n))''' Thread-1 is running Thread-2 is running ...... Thread-100 is running 主:0.5216062068939209 n:99 '''#不加鎖:未加鎖部分并發執行,加鎖部分串行執行,速度慢,數據安全 from threading import current_thread,Thread,Lock import os,time def task():#未加鎖的代碼并發運行time.sleep(3)print('%s start to run' %current_thread().getName())global n#加鎖的代碼串行運行lock.acquire()temp=ntime.sleep(0.5)n=temp-1lock.release()if __name__ == '__main__':n=100lock=Lock()threads=[]start_time=time.time()for i in range(100):t=Thread(target=task)threads.append(t)t.start()for t in threads:t.join()stop_time=time.time()print('主:%s n:%s' %(stop_time-start_time,n))''' Thread-1 is running Thread-2 is running ...... Thread-100 is running 主:53.294203758239746 n:0 '''# 有的同學可能有疑問:既然加鎖會讓運行變成串行,那么我在start之后立即使用join,就不用加鎖了啊,也是串行的效果啊# 沒錯:在start之后立刻使用jion,肯定會將100個任務的執行變成串行,毫無疑問,最終n的結果也肯定是0,是安全的,但問題是# start后立即join:任務內的所有代碼都是串行執行的,而加鎖,只是加鎖的部分即修改共享數據的部分是串行的# 單從保證數據安全方面,二者都可以實現,但很明顯是加鎖的效率更高. from threading import current_thread,Thread,Lock import os,time def task():time.sleep(3)print('%s start to run' %current_thread().getName())global ntemp=ntime.sleep(0.5)n=temp-1if __name__ == '__main__':n=100lock=Lock()start_time=time.time()for i in range(100):t=Thread(target=task)t.start()t.join()stop_time=time.time()print('主:%s n:%s' %(stop_time-start_time,n))''' Thread-1 start to run Thread-2 start to run ...... Thread-100 start to run 主:350.6937336921692 n:0 #耗時是多么的恐怖 ''')二、死鎖與遞歸鎖
進程也有死鎖與遞歸鎖,在進程那里忘記說了,放到這里一起說了。
所謂死鎖:是指兩個或兩個以上的進程或線程在執行過程中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去。此時稱系統處于死鎖狀態或系統產生了死鎖,這些永遠在互相等待的進程稱為死鎖進程,如下就是死鎖
2.1 死鎖
from threading import Lock as Lock import time mutexA=Lock() mutexA.acquire() mutexA.acquire() print(123) mutexA.release() mutexA.release()解決方法:遞歸鎖,在Python中為了支持在同一線程中多次請求同一資源,python提供了可重入鎖RLock。
這個RLock內部維護著一個Lock和一個counter變量,counter記錄了acquire的次數,從而使得資源可以被多次require。直到一個線程所有的acquire都被release,其他的線程才能獲得資源。上面的例子如果使用RLock代替Lock,則不會發生死鎖。
2.2 遞歸鎖RLock
from threading import RLock as Lock import time mutexA=Lock() mutexA.acquire() mutexA.acquire() print(123) mutexA.release() mutexA.release()三、典型問題:科學家吃面
3.1 死鎖問題
import time from threading import Thread,Lock noodle_lock = Lock() fork_lock = Lock() def eat1(name):noodle_lock.acquire()print('%s 搶到了面條'%name)fork_lock.acquire()print('%s 搶到了叉子'%name)print('%s 吃面'%name)fork_lock.release()noodle_lock.release()def eat2(name):fork_lock.acquire()print('%s 搶到了叉子' % name)time.sleep(1)noodle_lock.acquire()print('%s 搶到了面條' % name)print('%s 吃面' % name)noodle_lock.release()fork_lock.release()for name in ['哪吒','nick','tank']:t1 = Thread(target=eat1,args=(name,))t2 = Thread(target=eat2,args=(name,))t1.start()t2.start()3.2 遞歸鎖解決死鎖問題
import time from threading import Thread,RLock fork_lock = noodle_lock = RLock() def eat1(name):noodle_lock.acquire()print('%s 搶到了面條'%name)fork_lock.acquire()print('%s 搶到了叉子'%name)print('%s 吃面'%name)fork_lock.release()noodle_lock.release()def eat2(name):fork_lock.acquire()print('%s 搶到了叉子' % name)time.sleep(1)noodle_lock.acquire()print('%s 搶到了面條' % name)print('%s 吃面' % name)noodle_lock.release()fork_lock.release()for name in ['哪吒','nick','tank']:t1 = Thread(target=eat1,args=(name,))t2 = Thread(target=eat2,args=(name,))t1.start()t2.start()轉載于:https://www.cnblogs.com/nickchen121/p/11141739.html
總結
以上是生活随笔為你收集整理的Python程序中的线程操作-锁的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JS流程控制语句
- 下一篇: 最简化Selenium环境安装