1. 程式人生 > 實用技巧 >python 執行緒(thread)阻塞

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


完。