最近 Python 圈子里有个话题又双叒叕火了——自由线程(Free Threading)。
事情是这样的:
上个月 PyTorch 2.13 和 JAX v0.11 相继宣布不再给 CPython 3.13t 构建 wheel,全面转向 3.14t 和 3.15t。
紧接着 8月4号,Python 3.15 第一个候选版本发布,自由线程的稳定 ABI 正式落地。
这节奏,感觉 GIL 是真的要被抬走了。
但说实话,不少小伙伴听到「自由线程」四个字,反应基本是——”好像…
能让 Python 多核并行?”然后就没有然后了。
今天咱们就把它掰扯清楚。
GIL 是个什么东西?
想象一下:你开了一家奶茶店,店里只有一台收银机。
哪怕你雇了 8 个店员(8 核 CPU),顾客排了长队,但同一时刻,只能有 1 个人用收银机结账,其他 7 个人只能干瞪眼。
这台收银机,就是 Python 的 GIL(Global Interpreter Lock,全局解释器锁)。
import threading
import time
def 数数():
for i in range(50_000_000):
pass
# 单线程串行
start = time.time()
数数()
数数()
print(f"串行耗时: {time.time() - start:.2f}秒")
# 双线程"并行"
start = time.time()
t1 = threading.Thread(target=数数)
t2 = threading.Thread(target=数数)
t1.start(); t2.start()
t1.join(); t2.join()
print(f"双线程耗时: {time.time() - start:.2f}秒")
你会惊讶地发现:双线程并没有比串行快,甚至可能更慢。
因为 GIL 在背后卡着脖子——两个线程来回抢锁,上下文切换还额外浪费了时间。
说白了,GIL 让 Python 多线程在计算密集场景下变成了”假并行”。
那以前是怎么绕过去的?
Python 老司机们早就摸索出了几条绕路:
-
多进程(multiprocessing):每个进程有自己的 GIL,相当于开多家分店,每家都有独立收银机。但进程间通信(IPC)很重,内存开销大。 -
asyncio:协程本质上还是单线程,适合 I/O 密集(网络请求、文件读写),碰上 CPU 密集一样趴窝。 -
C 扩展:把计算密集的部分用 C 重写,在 C 代码里手动释放 GIL。
这几招虽然有用,但总有一种”打补丁”的感觉。
社区里喊”去掉 GIL”的声音喊了快二十年,一直没人能拿出一个大家都能接受的方案。
直到 Meta 的 Sam Gross 站了出来。
自由线程:把收银机拆了
自由线程的核心思路简单粗暴:直接让 GIL 变成可选项。
不再是一把大锁管所有东西,而是用一堆细粒度的小锁——给每个 Python 对象配一把微型的 PyMutex(只有 1 个字节),谁用谁锁,用完释放。
再配上原子引用计数和 mimalloc 线程安全内存分配器,让真正的多核并行成为可能。
# 自由线程 Python 下,同一段代码的表现
# 安装自由线程版本: pyenv install 3.14t
# 或者: PYTHON_GIL=0 python your_script.py
import sys
print("GIL 是否启用:", sys._is_gil_enabled()) # False!
import threading
counter = 0
lock = threading.Lock()
def 真并行了():
global counter
for _ in range(10_000_000):
with lock:
counter += 1
# 4 个线程能在 4 个核心上真正同时跑!
threads = [threading.Thread(target=真并行了) for _ in range(4)]
[t.start() for t in threads]
[t.join() for t in threads]
print(f"结果: {counter}")
在自由线程构建下,4 核 CPU 跑计算任务,速度真的能翻好几倍——不用再看 GIL 的脸色了。

现在能用吗?到哪一步了?
给你一张时间表,一看就明白:
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
3.14t |
|
|
|
|
|
|
|
|
重点来了:3.14 起,自由线程已经不是”实验性功能”了。
如果你用的是 macOS 或者 Linux,现在就能体验。
去 Python 官网下载页,选带 free-threaded 标记的安装包:
# pyenv 用户
pyenv install 3.14t
# 验证
python3.14t -c "import sys; print(sys._is_gil_enabled())"
# 输出: False
# 想临时切回 GIL?
PYTHON_GIL=1 python3.14t your_script.py
目前超过 50% 的 PyPI 热门包(NumPy、SciPy、Pandas、Pillow 等)已经提供了自由线程专用 wheel。
但是,别急着 All In
自由线程再香,也有几个坑需要先看清楚:
1. 单线程反而慢了 5-10%
没了 GIL 这个”大管家”,每次操作对象都要走原子引用计数和细粒度锁,单线程下确实比普通 Python 稍慢。
如果你的程序本来就是单线程跑跑脚本,没必要折腾。
2. 线程安全,还是得自己管
GIL 没了 ≠ 你的代码自动变安全了。
以前 GIL 默默帮你挡掉了很多竞态条件,现在你得自己用 threading.Lock 保护共享数据:
# GIL 时代"碰巧"能跑的代码,自由线程下可能翻车
# 危险:两个线程同时修改同一个 list
shared_list = []
# 线程 A: shared_list.append(1)
# 线程 B: shared_list.append(2)
# 可能丢数据!
# 正确的姿势
lock = threading.Lock()
with lock:
shared_list.append(1)
3. C 扩展兼容性
不是所有第三方库都适配了。
导入一个没声明支持自由线程的 C 扩展,GIL 会自动重新启用——相当于又回到了解放前。
最后
我的建议很简单:别盲目追新,但值得保持关注。
写 Web 后端的,asyncio 够你用到退休;
搞数据分析、科学计算的,自由线程真的能让你少喝好几杯咖啡。
Python 花了二十年戴上的这把枷锁,正在一场持续多年的接力赛中,被一点一点解下来。
能亲眼见证这个过程,说实话,挺酷的。

评论0