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

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

最后,感谢阅读,如果你喜欢本文,请一定要点赞/分享支持哈~

这一次,Python 真的有望告别 GIL 锁了?的更多相关文章

  1. 操作系统/应用程序、操作中的“并发”、线程和进程,python中线程和进程(GIL锁),python线程编写+锁

    并发编程前言: 1.网络应用 1)爬虫 直接应用并发编程: 2)网络框架 django flask tornado 源码-并发编程 3)socketserver 源码-并发编程 2.运维领域 1)自动 ...

  2. day 32 操作系统、线程和进程(GIL锁)

    一.操作系统/应用程序 a. 硬件 - 硬盘 - CPU - 主板 - 显卡 - 内存 - 电源 ... b. 装系统(软件) - 系统就是一个由程序员写出来软件,该软件用于控制计算机的硬件,让他们之 ...

  3. python GIL锁问题

    一.GIL是什么 官方解释: In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple na ...

  4. Python进阶----GIL锁,验证Cpython效率(单核,多核(计算密集型,IO密集型)),线程池,进程池

    day35 一丶GIL锁 什么是GIL锁:    存在Cpython解释器,全名:全局解释器锁.(解释器级别的锁) ​   GIL是一把互斥锁,将并发运行变成串行. ​   在同一个进程下开启的多个线 ...

  5. Python 线程----线程方法,线程事件,线程队列,线程池,GIL锁,协程,Greenlet

    主要内容: 线程的一些其他方法 线程事件 线程队列 线程池 GIL锁 协程 Greenlet Gevent 一. 线程(threading)的一些其他方法 from threading import ...

  6. Python高级笔记(一) -- GIL (全局解释器锁)

    1. GIL概念 (cpython历史遗留问题) 概念? 对Python多线程的影响? 编写一个多线程抓取网页的程序? 阐述多线程抓取程序是否比单线程性能有提升, 并解释原因. GIL:全局解释器锁, ...

  7. python爬虫之多线程、多进程、GIL锁

    背景: 我们知道多线程要比多进程效率更高,因为线程存在于进程之内,打开一个进程的话,首先需要开辟内存空间,占用内存空间比线程大.这样想也不怪,比如一个进程用10MB,开10个进程就得100MB的内存空 ...

  8. Python GIL锁

    GIL全局解释器锁:为了解决多线程修改同一块数据. python的线程是调用操作系统的源生线程,启动时就是调用C语言的C源生接口,python调用C语言接口的线程去执行任务时,必须上下文对应关系传给C ...

  9. Python大法之告别脚本小子系列—信息资产收集类脚本编写(下)

    作者:阿甫哥哥 原文来自:https://bbs.ichunqiu.com/article-1618-1.html 系列文章专辑:Python大法之告别脚本小子系列目录: 0×05 高精度字典生成脚本 ...

  10. python网络编程--线程GIL(全局解释器锁)

    一:什么是GIL 在CPython,全局解释器锁,或GIL,是一个互斥体防止多个本地线程执行同时修改同一个代码.这把锁是必要的主要是因为当前的内存管理不是线程安全的.(然而,由于GIL存在,其他特性已 ...

随机推荐

  1. C温故补缺(三):存储类声明符(auto,register,extern,static)

    auto,register,extern,static 四个存储类声明符,用于定义变量/函数的作用域和声明周期 ① auto:自动变量,即普通变量,在平时定义变量时会自动赋予其auto类型 被auto ...

  2. oracle 中模糊查询对like的代替insrt()函数 可以做到效率节约一倍以上

    昨天在处理一个字符拆分的功能时,用用到了insrt()函数,偶然发现其实特可以代替模糊查询的like,经多次测试可节约效率一倍以上. 代码如下: select distinct(a.deptname) ...

  3. ArcGIS 通过字段计算 设置顺序编码

    地块编号="前缀" & left("0000",4-len( [FID]+1)) & ([FID] +1)

  4. 零基础学习python的第一天整理——python的安装以及pycharm安装

    ​ 一.python的安装 首先我们来谈一谈python的安装,python的官网地址:Welcome to Python.org​编辑 进入官网后点击Downloads,然后选择自己对应的系统,比如 ...

  5. 有来实验室|第一篇:Seata1.5.2版本部署和开源全栈商城订单支付业务实战

    在线体验:Seata实验室 一. 前言 相信 youlai-mall 的实验室大家有曾在项目中见到过,但应该都还处于陌生的阶段,毕竟在此之前实验室多是以概念般的形式存在,所以我想借着此次的机会,对其进 ...

  6. 5V升压12.6V芯片电路图,三节锂电池充电

    三节3.7V的锂电池串联,11.1V和最大12.6V锂电池充电电路的解决方案.在应用中,一般使用低压5V,如USB口直接输入的给三串锂电池充电,还有是15V或者18V,20V输入降压给锂电池充电的两种 ...

  7. pandas中groupby的使用

    一.缘由 在爬取大量的数据之后,需要对数据进行分组的处理,于是就使用了groupby,但是我需要的并不是分组之后数据的聚合分析,我需要的是原生的某些数据.但是却找不到网上的相关案例.于是,我就自己尝试 ...

  8. Java单例模式的最佳实践?

    "读过书,--我便考你一考.茴香豆的茴字,怎样写的?"--鲁迅<孔乙己> 0x00 大纲 目录 0x00 大纲 0x01 前言 0x02 单例的正确性 new关键字 c ...

  9. 定制.NET 6.0的Middleware中间件

    大家好,我是张飞洪,感谢您的阅读,我会不定期和你分享学习心得,希望我的文章能成为你成长路上的垫脚石,让我们一起精进. 在本文中,我们将学习中间件,以及如何使用它进一步定制应用程序.我们将快速学习中间件 ...

  10. 小程序与app区别及测试点

    小程序和app区别 1. 用户获取渠道区别 小程序: 二维码.用户分享推荐.搜索小程序 APP: 需要去应用市场(或其他)下载 2. 下载.安装卸载 小程序: 不需下载安装,清除时直接删除小程序 AP ...