python 執行緒(thread)阻塞
本文連結:https://www.cnblogs.com/tujia/p/13684251.html
背景:來觀察測試一下python執行緒(Thread)的阻塞、普通執行緒和守護執行緒有什麼區別、執行緒池又是什麼
一、公共程式碼
首先先貼上一些公共程式碼,下面的例子都基於這份公共程式碼執行(注:替換xxx的內容)
import time import threading from concurrent.futures import ThreadPoolExecutor def worker(name): print('%s start...' % name) time.sleep(2) print('%s done.' % name) def xxx(): pass if __name__ == '__main__': xxx()
二、單執行緒阻塞
def 單執行緒阻塞(): t = threading.Thread(target=worker, args=('張三',)) t.start() # 阻塞 t.join() print('Finished')
執行結果:
解釋:阻塞執行緒的情況下,程式會先等待執行緒任務執行完,再往下執行其他程式碼
三、單執行緒不阻塞
def 單執行緒不阻塞(): t= threading.Thread(target=worker, args=('李四',)) t.start() print('Finished')
執行結果:
解釋:不阻塞執行緒的情況下,程式會直接往下走,執行緒任務是後完成的(因為我線上程任務里加了 sleep),類似於非同步;同時,我們還可以發現,程式(主執行緒)執行完最後一行程式碼之後,如果執行緒任務還沒完成,程式是不會馬上死掉的,還是會等執行緒任務執行完才會結束程式。
四、多執行緒的錯誤阻塞
def 多執行緒的錯誤阻塞(): t1 = threading.Thread(target=worker, args=('張三',)) t1.start() t1.join() t2 = threading.Thread(target=worker, args=('李四',)) t2.start() t2.join() print('Finished')
執行結果:
解釋:t1.join直接阻塞了程式,t2還沒start,t1.join阻塞程式直到t1的任務已完成。所以會看到張三 done之後,李四才能 start
五、多執行緒的正確阻塞
def 多執行緒的正確阻塞(): t1 = threading.Thread(target=worker, args=('張三',)) t2 = threading.Thread(target=worker, args=('李四',)) t1.start() t2.start() t1.join() t2.join() print('Finished')
執行結果:
解釋:需要將所以子執行緒都start之後,才能阻塞(join);執行緒任務也不是按順序完成了,哪個先完成,得看哪個執行緒任務耗時少,也有可能會同時完成(併發)
按下面程式碼,修改一下worker函式,給李四加一下速,再執行一次看看:
def worker(name): print('%s start...' % name) time.sleep(2 if name == '張三' else 1) print('%s done.' % name)
注:這次是李四先done了~
溫馨提示:測試完記得把 worker函式改回原來的樣子,下面例子是以原版的 worker為基礎的
六、多執行緒不阻塞
def 多執行緒不阻塞(): t1 = threading.Thread(target=worker, args=('張三',)) t2 = threading.Thread(target=worker, args=('李四',)) t1.start() t2.start() print('Finished')
執行結果:
解釋:參考上面單執行緒不阻塞↑,不阻塞的情況下,也是會等待全部執行緒任務執行完成才結束程式的。多執行緒有一定的並發現象
七、守護執行緒(後臺執行緒)阻塞
def 守護執行緒阻塞(): t1 = threading.Thread(daemon=True, target=worker, args=('張三',)) t2 = threading.Thread(daemon=True, target=worker, args=('李四',)) t1.start() t2.start() t1.join() t2.join() print('Finished')
執行結果:
解釋:這裡看著上面的普通執行緒沒有什麼區別的,具體的區別看下面↓↓↓
八、守護執行緒不阻塞
def 守護執行緒不阻塞(): t1 = threading.Thread(daemon=True, target=worker, args=('張三',)) t2 = threading.Thread(daemon=True, target=worker, args=('李四',)) t1.start() t2.start() print('Finished')
執行結果:
解釋:可以看到和”多執行緒不阻塞“很不一樣,主程式並不會等待子執行緒完成任務才結束。而是直接就結束了。這是守護執行緒(後臺執行緒)的一個特點:不阻塞的情況下,後臺執行緒(守護執行緒)會在主執行緒結束的時候自動死掉
九、守護執行緒不阻塞但主執行緒比較晚結束
def 守護執行緒不阻塞但主執行緒比較晚結束(): t1 = threading.Thread(daemon=True, target=worker, args=('張三',)) t2 = threading.Thread(daemon=True, target=worker, args=('李四',)) t1.start() t2.start() time.sleep(5) print('Finished')
執行結果:
解釋:這裡的主執行緒並沒有等子(守護)執行緒,只是主執行緒耗時並子執行緒還要久,子執行緒先執行完畢了
十、執行緒池
def 執行緒池(): with ThreadPoolExecutor(max_workers=3) as p: p.submit(worker, '張三') p.submit(worker, '李四') print('Finished')
執行結果:
解釋:執行緒池並沒有 join方法,但它預設就是阻塞的。執行結果基本和“多執行緒的正確阻塞”一樣,只是執行緒池比較方便管理~
本文連結:https://www.cnblogs.com/tujia/p/13684251.html
完。