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


完。 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM