Python 的 GIL 终于要凉了?聊聊自由线程

最近 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 的脸色了。

640-4

现在能用吗?到哪一步了?

给你一张时间表,一看就明白:

版本
时间
状态
Python 3.13
2024年10月
实验性,标记 “experimental”,单线程慢 20-40%
Python 3.14
2025年10月
正式支持,单线程只慢 5-10%,独立二进制 3.14t
Python 3.15
2026年10月(预计)
统一 ABI,一个扩展同时兼容 GIL/无GIL
Python 3.17-3.19
估计 2028-2030
GIL 默认关闭,甚至完全移除

重点来了: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 花了二十年戴上的这把枷锁,正在一场持续多年的接力赛中,被一点一点解下来。

能亲眼见证这个过程,说实话,挺酷的。

原文链接:https://www.zsiss.com/10251.html,转载请注明出处。
0

评论0

请先
响应式全屋定制家居网站模板11964
响应式全屋定制家居网站模板11964
刚刚 有人购买 去瞅瞅看

社交账号快速登录