Python:我 GIL 呢?
0X00 正文
看下面这段代码,可以看到这是一个经典中的经典问题:Python 中的全局解释锁 GIL。
py
import threading
import time
def count(n):
while n > 0:
n -= 1
N = 500_000_000
# 单线程:连续跑两次
start = time.perf_counter()
count(N)
count(N)
print(f"单线程跑两次:{time.perf_counter() - start:.2f} 秒")
# 多线程:两个线程各跑一次
start = time.perf_counter()
t1 = threading.Thread(target=count, args=(N,))
t2 = threading.Thread(target=count, args=(N,))
t1.start(); t2.start()
t1.join(); t2.join()
print(f"两线程各跑一次:{time.perf_counter() - start:.2f} 秒")我们都知道由于 GIL(全局解释锁) 的存在,Python 在运行 CPU 密集型的任务时不应该使用多线程,因为 Python 解释器并不能真正调动多个 CPU 核心并行执行,所以上面这个代码的输出就很好推断了,双线程“并发”的耗时应该和单线程跑两次的耗时几乎一样,所以它运行起来是这样的:

细心的你一定发现了,我运行了两次,居然出现了截然不同的结果!是的没错,Python 居然“多线程”了!
好了好了,现在来解释一下情况:Python 自从 3.13 开始就提供了一个叫做 free-threading 的版本了,这是文档。到了 3.14 之后就提供了官方支持。但是此时此刻 free-threading 还是一个单独的版本,所以你能看到我命令里用的是 python3.14t,这里的 t 就是 free-threading 的 tag 了。
0X01 好耶!我这就升级到这个版本
停,打住,换上 free-threading 之前至少需要了解下面这几个问题:
- Python 的 GIL 问题只在 CPU 密集型的任务里比较明显,如果你的程序一直在卡 IO 的话,即使切成了 free-threading 也不明显,甚至会变慢(因为官方说的 free-threading 是有单线程性能损失的,大约 5~10%)
- 依赖地狱,没错,你的依赖库和框架不一定准备好了。不过好在 Python 解释器加载三方依赖的时候会检查,如果一个库还没准备好的话,解释器会重新把 GIL 打开
- 需要自己操心线程安全了
所以目前是否使用 freet-threading 版本的结论和是否应该买一台 MacBook 是一样的:“当你不确定自己需要 free-threading 的时候,就不要用”。
如果这篇文章对你有帮助,可以请我喝杯咖啡 ☕
评论