全域性直譯器鎖(GIL)和阻塞執行緒
關於 Python 的 GIL已經寫 了很多。在處理多執行緒(不要與多程序混淆)應用程式時,它有時會引起混淆。
這是一個例子:
import math
from threading import Thread
def calc_fact(num):
math.factorial(num)
num = 600000
t = Thread(target=calc_fact, daemon=True, args=[num])
print("About to calculate: {}!".format(num))
t.start()
print("Calculating...")
t.join()
print("Calculated")
你可能希望線上程啟動後立即列印出 Calculating...
,我們希望計算在新執行緒中完成! 但實際上,你會看到計算完成後會列印出來。這是因為新執行緒依賴於 C 函式(math.factorial
),它將在執行時鎖定 GIL。
有幾種方法可以解決這個問題。第一個是在本機 Python 中實現你的階乘函式。這將允許主執行緒在你進入迴圈時獲取控制權。缺點是,這種解決方案將是一個很大較慢,因為我們沒有使用 C 函式了。
def calc_fact(num):
""" A slow version of factorial in native Python """
res = 1
while num >= 1:
res = res * num
num -= 1
return res
在開始執行之前,你還可以在一段時間內使用 sleep
。注意:這實際上不會允許程式中斷 C 函式內發生的計算,但它會允許主執行緒在生成後繼續,這是你可能期望的。
def calc_fact(num):
sleep(0.001)
math.factorial(num)