Python 全局解释器锁(GIL)的现状与变革
在 Python 生态中,全局解释器锁(Global Interpreter Lock,简称 GIL)是一个长期存在且备受争议的设计。它的主要作用是防止多个本地线程同时执行 Python 字节码,这导致 CPython 解释器无法实现真正的多线程并行执行。需要明确的是,本文讨论的 Python 解释器特指 CPython。
GIL 的历史背景与局限性
这把锁在 Python 的早期发展中具有积极的作用。在单核 CPU 时代,GIL 简化了内存管理模型,使得引用计数等机制能够安全地运行,避免了复杂的锁竞争问题。然而,随着硬件架构向多核 CPU 演进,GIL 成为了阻碍 Python 在多核环境下进行并行编程的主要瓶颈。
GIL 影响的主要是 CPU 密集型任务,比如科学计算、数值计算以及大规模数据处理任务。在这些场景下,开发者往往被迫使用多进程(multiprocessing)来绕过 GIL,但这带来了进程间通信开销大、内存占用高等问题。
在最近发布的官方文档及相关技术综述中,概括了 GIL 对科学计算(主要是 AI/ML)造成的四类核心问题:
- 并行化表达困难:GIL 导致许多并行化操作难以直接表达,影响了强化学习、DeepMind 相关研究、医学治疗模拟及生物信息学研究等领域的效率。
- 库可用性受限:GIL 影响了 Python 核心科学计算库的可用性,例如 PyTorch、scikit-learn、NumPy 等在多线程环境下的性能释放受到限制。
- GPU 资源利用不足:GIL 导致无法充分利用 GPU 资源,特别是在计算机视觉任务中,CPU 端的数据预处理和调度成为瓶颈。
- 模型部署复杂:GIL 导致难以高效部署 Python AI 模型,特别是基于神经网络的 AI 模型在高并发服务场景下的吞吐量受限。
社区呼声与历史尝试
社区中想要移除 GIL 的呼声以及尝试,此起彼伏,绵绵不绝,但这个话题一直悬而未决。抱怨、质疑、不满、不甘、期盼等这些诸多的情绪,不是那么容易平息的。然而,从一个积重已久的庞大的项目中移除一个根基性的设计,又谈何容易?
2023 新年刚过,这个话题又一次热了起来,又一轮对 GIL 的挑战开始了。这一次,事情似乎有了新的转机,这次也许能成功了呢?
PEP-703 提案详解
PEP-703 在今年 1 月 9 日新鲜出炉,虽然它目前仍是'草案'状态未被采纳,但是这份 PEP 的意义十分重大!这个 PEP 的作者是 Sam Gross,他是 nogil 项目的作者。经过一年多时间的沉淀,nogil 项目现在终于形成了正式的 PEP,这意味着它被采纳进 Python 主分支的可能性变大了一些。
PEP 的标题是《使 CPython 的 GIL 成为可选项》(Making the Global Interpreter Lock Optional in CPython),内容详实,正文超过 1 万字,这个体量的 PEP 绝对够得上排在所有 PEP 的前十了。
简单而言,这份提案提议给 CPython 增加一个构建时配置项 --disable-gil,作用是构建出一个线程安全的无 GIL 的解释器。为了实现无 GIL 的解释器,Python 底层的部分设计必须作出变更,内容可以概括成四类:
- 引用计数:需要确保引用计数的原子性,避免多线程竞争导致的内存泄漏或双重释放。
- 内存管理:分配器和垃圾回收机制需要适应无锁环境,可能需要引入更细粒度的内存池。
- 容器线程安全:字典、列表等内置容器的内部结构需要支持并发访问,或者提供相应的保护机制。
- 锁和原子 API:底层需要暴露更多的原子操作接口,供上层数据结构使用。
潜在挑战与解决方案
如果这份 PEP 被采纳实现的话,它会带来一个不容忽视的问题:Python 将发布两个不同版本的解释器,而第三方库也要相应地开发/维护/发布两个版本的软件包。这可能导致 ABI 不兼容,破坏现有的二进制分发体系。
PEP-703 的作者也考虑到了这个问题,他提出的解决方案是与 Anaconda 一起发布无 GIL 的 Python,同时在 conda 里集中发布管理那些兼容了新 Python 的库。考虑到 Anaconda 在科学计算与数值计算领域的强大影响力,此举既能较好地发挥 nogil Python 的用处,又能减少用户及三方库开发者面对两种发行版时的割裂感。
值得注意的是,nogil 的 Python 还有一个更大的问题,那就是会影响单线程程序的性能。基于 Python 3.11 版本,实现了有偏见的引用计数及永生对象后,Python 单线程性能会变慢 10%。尽管这个数值在最新的 nogil 原型版本上可以降低到 5%,但是,另外至少还有两项难以规避的性能下降点:
- 2% - 全局的自由列表(主要是元组和浮点数自由列表)带来的额外开销。


