Python 新提案:“废除”全局解释器锁 GIL | CPython 解释器或许会变得更快
共 2826字,需浏览 6分钟
·
2022-05-20 21:04
技术编辑:MissD丨发自 思否编辑部
公众号:SegmentFault
近日,开发者 Alex Waygood 在 Python 基金会博客中提到了上周刚刚举办的Python 语言峰会上关于 Python 语言的重大议题 —— “废除” Python 语言的全局解释器锁(GIL)。
“双刃剑”:CPython —— 解释器和编译器
多次尝试被废除:GIL 究竟该如何摆脱掉
直到此次的 Python 语言峰会上,Meta 高级工程总监 Sam Gross 在有关 “nogil”项目的主题中,提出了“废除 GIL ”的相关议题。
据悉,该提议是基于之前在 Python 中废除 GIL 的想法。Gross 最初在使用第三方代码的 Python 项目中遇到了问题,因此开始思考“如果没有 GIL”的话如何使得线程安全的进行。
前面提到过,全局解释器锁 GIL 一次只能在解释器中运行一个线程,所以当你可以保证一次只运行一个线程时,程序状态或许会更容易推理。但如果没有 GIL,引用计数、内存分配、方法解析顺序缓存和垃圾收集线程则会变得不安全。
那么,该如何摆脱 GIL 呢?
据报道,早前 Sam Gross 就专门对这一演变进行了讨论。由于 CPython 中的设计是“线程安全”,但它依赖于 GIL。想要摆脱 GIL,首先,就要对参考计数进行重大更改。
为了知道垃圾收集器是否可以释放内存中的对象,它会统计对该对象的所有引用。目前,引用计数是非原子性的,将所有引用计数操作更改为原子性操作会对性能造成巨大影响。
Sam Gross 在该提案中使用了一种称为“有偏引用计数”(biased reference counting )的技术,用于获取本地和共享引用。本地引用可以利用非原子性操作,拥有线程将本地引用和共享引用结合起来以跟踪所有权。这种方法非常适用于单线程对象,或者只被几个线程少量使用的对象。
在程序的生命周期中存在几个对象,如插入字符串、True、False 和 None,它们可以被标记为“不朽”(immortal),从而将它们的引用计数开销减少到零。通过利用引用计数字段中的最低有效位,对象被标记为“不朽”。经常访问但不能保证“不朽”的对象延迟了引用计数,这意味着唯一需要的引用计数是当引用存储在堆上时,此更改的一个副作用是无法立即回收对象,因为需要扫描堆栈以查找任何剩余的引用。
Sam Gross 用 mimalloc 替换了标准的 pymalloc 内存分配器,mimalloc 是 malloc 的一个替代品,提供了线程安全和性能。这种交换的好处是,这个分配器允许运行时在没有显式列表的情况下查找 GC 跟踪的对象。这是一个显著的性能提升,但这意味着不能只交换另一个与 malloc 兼容的分配器,而期望垃圾收集和收集具有相同的线程安全性。
Python 尚未决定是否删除 GIL
关于为何要删除 GIL 的问题,Python 基金会博客中解释称,“为了让 Python 在没有 GIL 的情况下有效地工作,必须向大多数代码中添加新锁,以确保其保持线程安全,但向现有代码中添加新锁可能非常困难,因为在某些领域可能会出现大幅放缓。”
此次,Sam Gross “删除 GIL”的新提议似乎已经受到了 Python 核心开发团队其他成员的“热情”欢迎。现在,要解决的主要问题是如何在 CPython 上实施如此巨大的变革。
据悉,CPython 的下一个版本(或为 CPython 3.11)预计将于 2022 年 10 月发布,不知道届时会不会有大更新,但报道称开发人员们尤其希望通过此更新获得更高的性能和对在 web 浏览器上下文中运行的支持的集成。
过去的一段时间里,由于 GIL 阻碍了语言的进发,开发者曾多次尝试在标准实现 CPython 中废除这种技术。此次,“删除 GIL”的新提议终于来了,尽管 Python 官方尚未就实施作出最终决定,但一切依旧值得期待。
参考链接:
https://www.html.it/magazine/python-cpython-piu-performante-con-nogil/
https://hackaday.com/2021/11/03/python-ditches-the-gils-and-comes-ashore/