
多年来,Python 开发者一直听到同样的批评:
Python 有一个 Global Interpreter Lock,所以线程无法真正并行运行 Python 代码。
对于传统的 CPython 构建版本来说,这种说法是准确的。
但情况已经发生了变化。
Python 3.13 引入了实验性的 free-threaded build,可以在没有 Global Interpreter Lock 的情况下运行。Python 3.14 又迈出了重要一步:free-threaded Python 现在已经得到正式支持。
那么,GIL 最终要消失了吗?
没那么快。
真正重要的变化是,GIL 在一种特殊的 CPython build 中已经变成了可选项。这与说 Python 已经彻底移除了 GIL 是完全不同的事情。
理解这一点,对于了解 Python 并发机制接下来会走向哪里很重要。
GIL 到底做了什么?
Global Interpreter Lock,通常称为 GIL,是 CPython 中用于保护解释器内部状态的一种机制。
在传统的 CPython build 中,同一时间只有一个线程可以在持有 GIL 的情况下执行 Python 代码。
这会带来一个重要影响。
创建多个线程,并不会自动让多个 CPU 密集型 Python 线程在多个 CPU 核心上同时执行 Python 字节码。
例如:
import threading
def calculate():
total = 0
for i in range(10_000_000):
total += i
threads = [
threading.Thread(target=calculate)
for _ in range(4)
]
for t in threads:
t.start()
for t in threads:
t.join()
在传统的 CPython build 中,这些线程不能简单地在四个 CPU 核心上同时执行 Python 代码。
这也是 Python 开发者过去在处理 CPU 密集型工作负载时,经常使用 multiprocessing 或释放 GIL 的 native extension 的原因之一。
多年来,GIL 也影响了 Python 库和框架的设计。
因此,移除它并不是简单地删除一个锁。
Python 3.13 改变了这一情况
PEP 703 提议让 GIL 在 CPython 中变成可选项。
该提案获得通过后,Python 3.13 引入了一种新的 build 配置:
./configure --disable-gil
这会生成一个 free-threaded 的 CPython build。
在这种模式下,多个 Python 线程可以在多个 CPU 核心上并行执行 Python 代码。
这是一次重大的架构变化。
不过,标准 CPython build 并没有突然变成无 GIL。
普通 build 仍然使用 GIL。
阅读“Python 正在移除 GIL”之类的标题时,很容易忽略这一点。
Python 3.13 实际上引入了两种模式:
Traditional CPython
|
+-- GIL enabled
Free-threaded CPython
|
+-- GIL disabled
free-threaded build 还带来了额外的兼容性和性能方面的考虑。
例如,依赖 GIL 的 C extension 不能自动认为自己在 free-threaded interpreter 中是安全的。
Python 3.14 又前进了一步
Python 3.14 又发生了一项重要变化。
Free-threaded Python 现在已经成为一个正式支持的 build,而不再是实验性功能。
这是一个重要的里程碑。
但“正式支持”仍然不意味着“GIL 已经被移除”。
PEP 779 描述的开发路线为 free-threaded Python 定义了三个阶段:
Phase I
Free-threading available
↓
Phase II
Free-threading officially supported
↓
Phase III
Free-threading becomes the default
Python 3.13 进入了第一阶段。
Python 3.14 进入了第二阶段。
第三阶段尚未发生。
Python Steering Council 已明确表示,让 free-threading 成为默认模式仍然是未来需要做出的决定,并取决于性能、生态系统支持以及社区采用情况等因素。
因此,说“Python 3.14 移除了 GIL”会产生误导。
更准确的说法是:
Python 3.14 正式支持一种 free-threaded build,在这种 build 中可以禁用 GIL。
这一点比表面上看起来更加重要。
移除 GIL 在技术上代价很高
为什么 Python 没有早些年直接移除 GIL?
因为 GIL 历史上提供的不仅仅是一个并发限制。
它还简化了 CPython 实现中的许多方面。
其中一个例子就是引用计数。
CPython 使用引用计数作为内存管理的重要组成部分。在 GIL 保护解释器状态的情况下,引用计数操作可以依赖这样一个事实:多个线程不会同时修改相同的解释器状态。
没有 GIL 后,解释器就需要其他机制来保证线程安全。
因此,PEP 703 涉及对以下领域的大量修改:
reference counting
memory allocation
object access
built-in containers
locking
atomic operations
garbage collection
C API
实现中还引入了 biased reference counting、immortal objects、deferred reference counting 和 per-object locking 等技术,用来降低 free-threaded interpreter 中的线程安全成本。
这些技术的目标是降低 free-threaded interpreter 中 atomic reference counting 以及其他同步机制带来的开销。
这说明了一个重要问题:
GIL 从来都不只是解释器中的一把普通锁。
它与 CPython 的实现有着非常深的联系。
移除它提供的保护,需要重新设计许多内部机制。
Free-Threading 并不是没有代价的
还有一个重要细节。
移除 GIL 并不会让每个 Python 程序都自动变快。
free-threaded interpreter 会产生额外的同步等运行时开销。
在 Python 3.13 中,free-threaded build 在 pyperformance 基准测试套件上的单线程性能开销大约为 40%,主要原因是 specializing adaptive interpreter 被禁用了。Python 3.14 重新启用了这个 interpreter,并进行了大量改进,将单线程性能损耗降低到了大约 5–10%,具体取决于平台和 C compiler。
PEP 779 将**单线程性能损耗不超过 15%**设定为 Phase II 的验收指标,而 Python 3.14 已经达到这一要求。
这种权衡很直接:
Traditional build
Single thread
↓
Lower overhead
Multiple CPU-bound threads
↓
GIL limits parallel execution
相比之下:
Free-threaded build
Single thread
↓
Some additional overhead
Multiple CPU-bound threads
↓
Can execute Python code in parallel
对于能够从真正的多核并行中受益的工作负载,这种权衡可能是值得的。
对于主要是单线程的工作负载,传统 build 可能仍然具有优势。
这也是 Python 核心开发者对是否让 free-threading 成为默认模式保持谨慎的原因之一。
需要注意的是,即使在传统 GIL 下,IO 密集型 Python 代码长期以来也能够有效使用线程。Free-threading 主要为 CPU 密集型 Python 字节码解锁了并行能力。
生态系统是另一个大问题
CPython interpreter 只是 Python 生态系统的一部分。
大量 Python 软件依赖 C 和 C++ extension modules。
NumPy、科学计算软件包、数据库驱动、图像处理库以及 machine-learning frameworks 等库,都可能通过 C API 与 CPython 交互。
如果一个 extension 假设 GIL 会保护某些内部状态,那么简单地禁用 GIL 就可能暴露出 race condition。
因此,Python 的 free-threaded build 采用了一种保守的处理方式。
如果导入的 C extension 没有声明自己支持 free-threading,CPython 可以在加载它时自动重新启用 GIL,并发出 warning。
这意味着,一个程序即使运行在 free-threaded Python build 上,也可能因为使用了不兼容的 extension 而仍然启用 GIL。
这也是为什么:
“我安装了 Python 3.14,所以我的程序已经没有 GIL 了。”
并不一定正确。
你需要考虑实际使用的 interpreter build,以及应用程序所使用的库。
这对 Python 开发者意味着什么?
对于大多数开发者来说,没有必要因为 free-threaded Python 的出现就重写现有应用程序。
传统的 GIL-enabled build 仍然存在。
更值得关注的问题,是那些高度 CPU 密集并且天然适合并行的应用程序会发生什么。
对于这些应用,free-threading 提供了一种新的可能性。
过去可能会直接选择 multiprocessing:
One process
↓
Multiple processes
↓
Separate Python interpreters
↓
Higher communication and memory costs
开发者最终可能可以使用:
One process
↓
Multiple Python threads
↓
Multiple CPU cores
这可能简化某些架构,并减少对基于进程的解决方案的需求。
但这并不意味着 threading 突然就成为所有工作负载的最佳解决方案。
并发仍然需要仔细处理同步。
竞态条件(race condition)仍然存在。
共享可变状态仍然需要保护。
设计不佳的多线程代码仍然可能很难调试。
移除 GIL 消除了一个全局限制,但并没有消除并发编程本身的复杂性。
那么,GIL 要消失了吗?
最准确的答案是:
GIL 正在变成可选项,但它还没有消失。
Python 的方向已经很明确:
GIL required
↓
GIL optional
↓
Free-threading officially supported
↓
???
最后一步仍然是一个开放问题。
Python 社区现在正在收集真实世界中的数据,包括性能、内存使用、C extension 兼容性、生态系统支持以及开发者体验。
PEP 779 明确指出,让 free-threaded Python 成为默认模式,是一个与让它获得正式支持不同的决定。
这个区别很重要。
故事已经不再是“Python 无法移除 GIL”。
CPython 已经证明,它可以在没有 GIL 的情况下运行。
更值得关注的问题是,Python 生态系统能否发展到这样一个阶段:free-threading 带来的收益能够持续超过它所带来的成本。
答案将取决于真实的应用程序、真实的 benchmark,以及真实的库支持情况。
所以,当你看到这样的标题:
“Python 终于要移除 GIL 了!”
更值得问的问题是:
使用的是哪个 Python build、哪个版本、哪些库,以及在什么工作负载下?
GIL 的故事已经不再是它能不能消失。
真正的问题是,Python 能否让一个无 GIL 的世界对大多数开发者来说变得切实可用。
以上就是“Python 的 GIL 真的要消失了吗?别急着下结论”的详细内容,想要了解更多Python教程欢迎持续关注编程学习网。
扫码二维码 获取免费视频学习资料

- 本文固定链接: http://www.phpxs.com/post/14536/
- 转载请注明:转载必须在正文中标注并保留原文链接
- 扫码: 扫上方二维码获取免费视频资料