全局解释器锁(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)