python中gil锁和线程锁(这一次,Python 真的有望告别 GIL 锁了?)
Python 中有一把著名的锁——全局解释器锁(Global Interpreter Lock ,简写 GIL) ,它的作用是防止多个本地线程同时执行 Python 字节码,这会导致 Python 无法实现真正的多线程执行 。(注:本文中 Python 解释器特指 CPython)
这把锁在 Python 的早期发展中具有积极的作用(单核 CPU 时代) ,然而 ,它阻碍了 Python 在多核 CPU 上的并行编程 ,引起了开发者们与日俱增的诟病 。
GIL 影响的主要是 CPU 密集型任务 ,比如科学计算与数值计算任务。
在最近发布的 PEP-703 中 ,它概括了 GIL 对科学计算(主要是 AI/ML)造成的四类问题:
GIL 导致许多并行化操作难以表达(影响强化学习 、DeepMind 、医学治疗及生物研究等领域) GIL 影响了 Python 库的可用性(例如 PyTorch 、scikit-learn 、NumPy) GIL 导致无法充分利用 GPU 资源(例如计算机视觉任务) GIL 导致难以部署 Python AI 模型(例如基于神经网络的 AI 模型)社区中想要移除 GIL 的呼声以及尝试 ,此起彼伏 ,绵绵不绝 ,但这个话题一直悬而未决 。
抱怨 、质疑 、不满 、不甘 、期盼等这些诸多的情绪 ,不是那么容易平息的 。然而,从一个积重已久的庞大的项目中移除一个根基性的设计 ,又谈何容易?
2023 新年刚过 ,这个话题又一次热了起来,又一轮对 GIL 的挑战开始了 。
这一次 ,事情似乎有了新的转机 ,这次也许能成功了呢?
PEP-703 在今年 1 月 9 日新鲜出炉,虽然它目前仍是“草案 ”状态未被采纳 ,但是这份 PEP 的意义十分重大!
(注:每个 Python 学习者都应该基本了解 PEP ,建议阅读《学习Python ,怎能不懂点PEP呢? 》)
这个 PEP 的作者是 Sam Gross ,他是 nogil 项目的作者 。Python猫的老读者应该有印象 ,我们在 2021 年曾翻译过他与 Python 核心开发者们的一次研讨会的纪要 ,这份纪要里概括了 nogil 的主要设计思路 ,同时回答了核心开发者们最为关注的约 20 个问题 。
经过一年多时间的沉淀 ,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 将发布两个不同版本的解释器 ,而第三方库也要相应地开发/维护/发布两个版本的软件包 。
PEP-703 的作者也考虑到了这个问题 ,他提出的解决方案是与 Anaconda 一起发布无 GIL 的 Python ,同时在 conda 里集中发布管理那些兼容了新 Python 的库 。
考虑到 Anaconda 在科学计算与数值计算领域的强大影响力 ,此举既能较好地发挥 nogil Python 的用处 ,又能减少用户及三方库开发者面对两种发行版时的割裂感。
值得注意的是 ,nogil 的 Python 还有一个更大的问题 ,那就是会影响单线程程序的性能 。
基于 Python 3.11 版本 ,实现了有偏见的引用计数及永生对象后,Python 单线程性能会变慢 10% 。
尽管这个数值在最新的 nogil 原型版本上可以降低到 5% ,但是 ,另外至少还有两项难以规避的性能下降点:
2% - 全局的自由列表(主要是元组和浮点数自由列表) 1.5% - 集合中每个对象的互斥锁(字典 、列表、队列)单线程的代码才是最广泛的使用场景,可以说这会影响到每一个 Python 用户。任何试图移除 GIL 的项目都不可避免要面临这项挑战 。
尽管存在着以上的两大问题 ,但 PEP-703 还是很有可取之处的 。
比如 ,相比于 2015 年提出的著名的 Gilectomy 项目(由 GIL ectomy 两个单词组合而成,ectomy 是一个医学上的术语“切除术 ”) ,nogil 在单线程的性能上要快得多 ,同时可扩展性也更好。
比如 ,相比于 2021 年火热的“香农计划”的作者 Eric Snow 提出的 PEP-684 方案(给每个子解释器创建 GIL) ,后者一方面需要实现作为前提的多个 PEP(如 PEP-554 、PEP-683) ,另一方面需要用户处理多子解释器间共享变量的麻烦 。
在香农计划的《Python 3.12 目标》中 ,PEP-554 与 PEP-684 已经囊括在内了 ,版本目标是充分利用 Python 的子解释器 ,让子解释器使用各自的 GIL ,从而实现多线程的并行 。
好消息是,3.12 的计划跟本文的主角 PEP-703 并不冲突 。事实上 ,它们的很多设计细节是一致的 ,也就是说,这两套对于 GIL 的改造方案是可以共存的 ,它们相互促进 ,事半功倍!
香农计划有 Python 之父 Guido van Rossum 站台,还有财大气粗的微软支持着一支豪华的团队投入开发(含 Guido 和 Eric Snow) ,因此 ,多解释器多 GIL 的方案很可能会更快落地 。
而 PEP-703 有 PSF 首位全职开发者 Łukasz Langa 的倾力支持 ,社区的反响也不错 ,我觉得它今后落地的希望也挺大!
无论如何 ,这次香农计划和 PEP-703 掀起的对 GIL 的挑战 ,比以往所有的尝试都更猛烈 ,更有成功的可能 ,让人不由得心生欢欣之喜~~
但愿它们实现的一天不会太远吧 。
最后 ,感谢阅读,如果你喜欢本文 ,请一定要点赞/分享支持哈~
创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!