
Python 多執行緒(Threading) — Basic Operation & Join
現在電腦的 CPU 都有許多的核心(可以把核心想像成一顆顆小 CPU 例如4核心的 CPU 就可以想像有4顆小 CPU 被包在1顆 CPU 裡面),如果要充分 CPU 多核心的運算能力,我們可以考慮採用多執行緒或是多行程之類的平行化技術。在 Python 裡面我們可以利用一個叫做threading的庫來達到這件事。
基本操作
我們首先來了解 threading 這個庫的一些基本操作。
import threading
threading.active() # 得到已經啟用的執行緒數量
threading.enumerate() # 查看所有執行緒的訊息
threading.current_thread() # 查看運作中執行緒的訊息增加新的執行緒
了解完一些基本的 threading 這個庫的一些基本操作後,我們來了解一下要如何增加一個新的執行緒。
要增加一個新的執行緒,我們必須要先有一個讓這個執行緒去執行的方法,我們先將這個程式簡單寫成
def thread_job():
print("This is a thread of %s" % threading.current_thread())從上面可以看到我們要給執行緒執行的方法是列印出執行緒的訊息,在定義完要給執行緒執行的方法後我們要新增一個執行緒並且啟動它,我們可以利用這兩行程式碼去完成
thread = threading.Thread(target=thread_job) # 定義執行緒thread.start() # 讓執行緒開始工作在第一行中的 target 參數是帶鰾我們要這個執行緒去完成的任務,需要自己定義。
執行緒裡的 Join
在說明 python 執行緒裡的 join 在做什麼之前我們先來看一個範例
import time
import threadingdef thread_job():
print("T1 start")
time.sleep(1)
print("T1 finish")added_thread = threading.Thread(target=thread_job)
added_thread.start()
print("All done")
以上的程式應該不難理解我們增加了一個新的執行緒,這個執行緒會執行 thread_job 這個方法。接下來問題來了我們預期中執行的結果應該是這樣
T1 start
T1 finsih
all done但是實際結果卻是
T1 start
all done
T1 finsih在執行緒還沒完成的時候就印出 all done 如果我們要遵循我們想像中的樣子我們可以改成這樣
added_thread.start()
added_thread.join()
print("All done")藉由以上的例子來說我們可以使用 join 來控制整體執行的順序以便規避掉不必要的麻煩,但是在使用 join 的順序是非常關鍵的,舉個例子我們在增加一個新的執行緒T2並且在T1被啟動後啟動T2
import time
import threadingdef T1():
print("T1 start")
time.sleep(1)
print("T1 finish")def T2():
print("T2 start")
print("T2 finish")thread_1 = threading.Thread(target=T1)
thread_2 = threading.Thread(target=T2)
thread_1.start()
thread_2.start()
print("all done")
這段程式輸出的其中一個結果會是
T1 start
T2 start
T2 finsih
all done
T1 finish為什麼說是一種呢?是因為 all done 的出現出取決於 thread_1 以及 thread_2 的執行速度因此 T2 finsih 是有可能會出現在 all done 之後。然而這樣雜亂的執行方式絕對不是我們可以忍受的,因此我們可以使用 join 來控制順序。
我們先試試在 T1 啟動後 T2 啟動前加入 join
thread_1.start()
thread_1.join()
thread_2.start()
print("All done")輸出結果為
T1 start
T1 finish
T2 start
all done
T2 finsih看到了嗎?T2會在T1結束後才開始執行,相同的如果我們將 join 放在 T2 啟動後的結果會變成這樣
T1 start
T2 start
T2 finish
T1 finsih
all doneT2在T1之後開始運作而且因為T1有加上一秒鐘的暫停所以T2的執行量會比T1還要小因此會比T1還要早完成而且T1也因為加了 join 所以 all done 會在 T1 完成後顯示。