GIL 锁或将在 CPython 中成为可选项
哈喽大家好,我是咸鱼
几天前有媒体报道称,经过多次辩论,Python 指导委员会打算批准通过 PEP 703 提案,让 GIL(全局解释器)锁在 CPython 中成为一个可选项
PEP 703 提案主要目标是使 GIL 变成可选项,即允许 Python 解释器在特定情况下不使用GIL
这将允许 Python 在多核处理器上更好地利用并行性,从而提高多线程程序的性能
PEP 703 提案建议新增一个配置项 --disable-gil
,加了这个选项之后就可以关闭 GIL 锁,如果想要开启 GIL 锁,把 --disable-gil
去掉即可
关于 PEP 703 提案的具体内容有兴趣的小伙伴们可以去看一下
PEP 703 提案:https://peps.python.org/pep-0703/
接下来我们来看下外媒的这篇报道吧!
原文:https://www.infoworld.com/article/3704248/python-moves-to-remove-the-gil-and-boost-concurrency.html
译文如下:
经过多次辩论,Python 指导委员会打算批准 PEP 703 提案——”使全局解释器锁在 CPython 中可选“
PEP 703 提案是多年来尝试移除 Python GIL 锁的最终结果。GIL 锁的移除消除了多线程的主要障碍,使得 Python 成为真正的多核语言,并且显著提高其并行工作负载的性能
有了 PEP 703 提案,Python 中对多线程和并发的一流支持离成为现实又近了一步
为什么要移除 GIL ?
在 python 中,其内存管理系统通过维护每个对象的引用数量来跟踪对象的使用情况(Python 的引用计数机制)
当对象的引用计数减少为 0 时,系统就会删除该对象
由于 Python 诞生于多处理器系统很少见且多核处理器还未出现的时代,所以这种引用计数机制不是线程安全的
相反,Python 通过一次只允许一个线程访问对象来实现线程安全,这便是 GIL 的目的
这些年来许多项目都尝试移除 GIL,它们确实能够使多线程程序运行地更快,但代价是降低了单线程程序的性能
鉴于绝大多数 Python 应用程序都是单线程,所以这是一个糟糕的权衡。尽管对 GIL 的改进提升了 Pyhton 对多线程应用程序的处理,但仍旧是一个严重的瓶颈
Python 的核心开发人员最终决定从 CPython 中移除 GIL,但前提是它可以在不减慢单线程程序速度的情况下完成
没了 GIL,Python 该如何运行?
当前关于 Python 的无 GIL 版本的提案都提到了使用多种技术来使引用计数线程安全,并且维持单线程程序的速度不变或者仅对其产生最小的影响
下面是一些关于无 GIL 版本的提案:
- Biased reference counting(带偏见的引用计数)
单个线程访问的对象的引用计数与多个线程访问的对象的引用计数处理方式不同(单线程的更快一点)
由于大多数对象只被一个线程访问,因此对单线程程序的影响被降到最低
- Immortalization(永生)
某些对象(如 None
)永远不会被回收,因此不需要跟踪它们的引用计数
- Thread-safe memory allocation(线程安全的内存分配)
一个新的 CPython 对象内存分配系统将使垃圾收集器中的对象跟踪更容易,并以线程安全的方式分配内存
- Deferred reference counting(延迟引用计数)
某些对象(如模块中的顶级函数)的引用计数可以安全地延迟。这样可以节省时间和资源
- A revised garbage collector(修改后的垃圾收集器)
CPyhton 垃圾收集器清楚循环对象的引用(比如两个或多个对象互相引用)
无 GIL构建对垃圾收集器做了许多更改,例如删除用于跟踪对象的“生成”系统
如何逐步引入无 GIL 的 Python?
实施 PEP 703 是一个长期项目,将会在几年内分成多个阶段进行。在此期间,CPython 解释器先过渡到使 no-GIL 版本可选,然后是支持,最后成为标准
为了实现这个目标,CPython 的开发者将会为 CPython 添加一个实验性的 ’no-GIL‘ 构建模式,以便大家可以在有或没有 GIL 的情况下编译 CPython 的版本
最终,no-GIL 构建将成为默认值
下面则是相关的计划:
1、no-GIL 是可选项
对于 CPython 开发人员和 Python 社区来说,no-GIL CPython 的第一个版本将是实验性
这个实验阶段有几个目标:
- 首先让 Python 社区的其他成员参与进来。对 Python 的任何重大更改都需要更广泛的Python 社区的支持。实验性版本为 Python 用户提供了一种安全地试验测试其代码的方法,并且能够观察非线程和线程代码的行为方式
- 其次让 Python 发行版可以选择(而不是”要求“)提供 no-GIL 的 Python。像 Conda 或WinPython 这样的 Python 发行版需要保证与原有的 CPython 兼容。在过渡阶段,安装的时候可以提供常规或者 no-GIL 版本的 CPython 选项,这将允许 Conda 或WinPython 用户选择最适合他们需求的版本
- 最后确定 no-GIL 项目是否值得。如果社区大规模尝试 no-GIL 的构建后对结果不满意,CPython 核心开发人员保留退出的权利。双重构建意味着在短期内会增加维护负担,但如果 no-GIL 项目被证明不值得,他们也有退路
2、支持 no-GIL Python
下一阶段将提供 no-GIL 构建作为 CPython 支持的替代构建
用户可以选择安装 no-GIL 或 GIL 版本,其中任何一个版本都是正式支持的 CPython 版本,可以接收错误修复、安全补丁和更新
这个阶段的一大目标是设置一个期限,使 no-GIL 成为默认值
这可能与其他 Python 功能的弃用和删除在同一时间线上发生——至少两三个版本,也意味着至少两到三年
3、no-GIL 成为默认
最后阶段是将 CPython 的 no-GIL 版本作为默认版本,并从 CPython 中删除所有与 GIL 相关的代码
”我们不想等待太久“,CPython 核心开发人员 Thomas Wouters 写道,“因为拥有两种通用的构建模式可能会给社区带来沉重的负担(例如,它可以将测试资源和调试场景加倍),但我们也不能急于求成。我们认为可能需要长达五年的时间才能达到这个阶段
移除 GIL 的最大挑战
尽管技术挑战令人生畏,但这项计划的最大挑战不仅仅是技术挑战。更大的问题是如何使 Python 生态系统的其余部分与这些变化保持一致且确保 no-GIL 的 Python 不会产生比它解决的问题更多的问题
根据 Wouters 的说法,”...适应非 GIL 构建所需的第三方代码的任何更改都应该只适用于 GIL 构建(尽管仍然需要解决与旧 Python 版本的向后兼容性问题)“
如上所述,另一个重大挑战是”带领Python社区的其他成员,” Wouters 说,“……确保我们想要做出的改变,以及我们希望他们做出的改变,是可以接受的
“在我们承诺完全切换到 no-GIL 构建之前,我们需要看到社区对它的支持,” Wouters说。“我们不能只是改变默认值,然后期望社区找出他们需要做些什么来支持它”
Python 社区在从 Python 2 过渡到 Python 3 的过程中经历了巨大的成长痛苦,因此任何像移除 GIL 这样的重大更改都必须完全向后兼容
正如 Wouters 所说,“我们不希望再出现 Python 3 的情况。”
不过在危险和挑战之外,还有一个巨大的回报——Python 最终支持了程序员在 21 世纪所期望的并行性