这一次,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 的挑战,比以往所有的尝试都更猛烈,更有成功的可能,让人不由得心生欢欣之喜~~

但愿它们实现的一天不会太远吧。

目录
相关文章
|
3月前
|
数据采集 存储 安全
如何确保Python Queue的线程和进程安全性:使用锁的技巧
本文探讨了在Python爬虫技术中使用锁来保障Queue(队列)的线程和进程安全性。通过分析`queue.Queue`及`multiprocessing.Queue`的基本线程与进程安全特性,文章指出在特定场景下使用锁的重要性。文中还提供了一个综合示例,该示例利用亿牛云爬虫代理服务、多线程技术和锁机制,实现了高效且安全的网页数据采集流程。示例涵盖了代理IP、User-Agent和Cookie的设置,以及如何使用BeautifulSoup解析HTML内容并将其保存为文档。通过这种方式,不仅提高了数据采集效率,还有效避免了并发环境下的数据竞争问题。
如何确保Python Queue的线程和进程安全性:使用锁的技巧
|
1月前
|
Java C语言 Python
解析Python中的全局解释器锁(GIL):影响、工作原理及解决方案
解析Python中的全局解释器锁(GIL):影响、工作原理及解决方案
32 0
|
2月前
|
存储 算法 Java
关于python3的一些理解(装饰器、垃圾回收、进程线程协程、全局解释器锁等)
该文章深入探讨了Python3中的多个重要概念,包括装饰器的工作原理、垃圾回收机制、进程与线程的区别及全局解释器锁(GIL)的影响等,并提供了详细的解释与示例代码。
27 0
|
3月前
|
数据采集 Java Python
python 递归锁、信号量、事件、线程队列、进程池和线程池、回调函数、定时器
python 递归锁、信号量、事件、线程队列、进程池和线程池、回调函数、定时器
|
3月前
|
消息中间件 存储 安全
python多进程并发编程之互斥锁与进程间的通信
python多进程并发编程之互斥锁与进程间的通信
|
4月前
|
数据挖掘 Python
🚀告别繁琐!Python I/O管理实战,文件读写效率飙升的秘密
【7月更文挑战第29天】在 Python 编程中,高效的文件 I/O 对性能至关重要。
49 4
|
4月前
|
前端开发 API 数据库
告别繁琐,拥抱简洁!Python RESTful API 设计实战,让 API 调用如丝般顺滑!
【7月更文挑战第23天】在Python的Flask框架下构建RESTful API,为在线商店管理商品、订单及用户信息。以商品管理为例,设计简洁API端点,如GET `/products`获取商品列表,POST `/products`添加商品,PUT和DELETE则分别用于更新和删除商品。使用SQLAlchemy ORM与SQLite数据库交互,确保数据一致性。实战中还应加入数据验证、错误处理和权限控制,使API既高效又安全,便于前端或其他服务无缝对接。
55 9
|
3月前
|
安全 Python
Python 中的全局解释器锁(GIL)详解
【8月更文挑战第24天】
83 0
|
4月前
|
数据采集 API 开发者
🚀告别网络爬虫小白!urllib与requests联手,Python网络请求实战全攻略
【7月更文挑战第29天】在广阔的网络世界里,Python以其简洁的语法和强大的库支持成为网络爬虫开发的首选。本文聚焦于两大网络请求库——urllib和requests。urllib是Python内置库,虽API稍显复杂,却有助于理解HTTP本质。示例代码展示了如何使用`urlopen`函数发起GET请求并读取网页内容。相比之下,requests库则更加人性化,极大地简化了HTTP请求流程,使开发者能更专注于业务逻辑。
46 1
|
4月前
|
数据可视化 数据挖掘 Python
告别枯燥数字,拥抱视觉盛宴!Python 数据分析中的数据可视化艺术,你 get 了吗?
【7月更文挑战第23天】在数据驱动时代,Python的Matplotlib、Seaborn与Plotly等库使数据可视化成为洞察信息的关键工具。不仅转化数字为图形,更是视觉传达故事。示例代码展示从基础图表到箱线图、小提琴图和热力图的创建过程,强调选择合适图表、简洁设计与色彩的重要性。Python赋能数据可视化,开启数据理解新视角,助于揭示模式、辅助决策。✨📊💡 (总计239字符)
57 7