我们知道,在 CPython 中,有一个全局解释器锁,英文叫 global interpreter lock,简称 GIL,是一个互斥锁,用来保护 Python 世界里的对象,防止同一时刻多个线程执行 Python 的字节码,从而确保线程安全,这导致了 Python 的线程无法利用多核 CPU 的优势,也有人说 Python 的多线程是伪线程,性能不高,那么 Python 将来有可能去除 GIL 吗?

要回答这个问题,先从 GIL 的起源进行分析。

GIL 的起源

Python 第一次发布是在 1991 年,当时的 CPU 都是单核,单核中,多线程主要为了一边做IO,一边做 CPU 计算而设计的,Python 编译器是由 C 语言编写的,因此也叫 CPython,那时候很多编程语言者没有自动内存管理的功能,为了实现自动垃圾回收,Python 为每一个对象进行了引用计数,当引用计数为 0 的时候说明该对象可以回收,从而释放内存了,比如:

>>> import sys

>>> data = { 'gzh': 'Python七号'}

>>> var1 = data

>>> sys.getrefcount(data)

3

>>>

这里 data 对象就有 3 个引用, 一个是本身,一个是变量 var1,一个是 getrefcount 函数的参数,如果此时又有一个线程引用了 data,那么引用计数再增加 1,如果某个线程使用了 data 后运行结束,那么引用计数就减少 1,多线程对同一个变量「引用计数」进行修改,就会遇到 race conditions(竞争),为了避免 race conditions,最简单有效的办法就是加一个互斥锁。

如果对每一个对象都加锁,有可能引发另一个问题,就是死锁,而且频繁的获取和释放会导致性能下降,最简单有效的方法就是加一个解释器锁,线程在执行任何字节码时都先获取解释器锁,这就避免了死锁,而且不会有太多的性能消耗。当时 CPU 都是单核,而且这种 GIL 设计简单,并不会影响性能,因此有一直沿用至今天。GIL 存在最主要的原因,就是因为 Python 的内存管理不是线程安全的,这就是 GIL 产生并存在的主要缘由。

尝试消除 GIL

CPU 进入多核时代后,可以同时做多个计算任务, GIL 才真正变成问题。在 1999 年,有个叫 Greg Stein 的人基于 Python 1.5 版本消除了 GIL,取代代之的是在可变数据结构上加上更细粒度的锁,也提交了补丁用于去除对全局可变对象的依赖,然后在标准测试中显示单线程比不去除 GIL 慢了近 2 倍,测试的机器还是当时性能最好 Windows 机器。也就是说除去了 GIL 后,你使用 2 个 CPU 才能获取比原来 1 个 CPU 稍微好一点的性能,这种提升就是得不偿失,Greg Stein 的尝试也就失败告终。

Python 之父 Guido van Rossum 也欢迎社区的志愿者去尝试去除 GIL,只要不降低单线程的性能,但他也提到,去掉 GIL 不是一件容易的事。

Python 开发者邮件列表中也偶尔会有去除 GIL 的议题,但是以下需求必须满足:

简单。从长远来看该方案必须是可实施、可维护的。

并发。去除 GIL 必须能提升多线程的性能。

速度。 去除 GIL 不能降低单线程的性能。

满足 CPython 的特性。该方案必须支持 CPython 的功能,比如 __del__ 和弱引用。

API 的兼容性。 该方案应与所有现有CPython扩展使用的宏在源方面兼容。

及时销毁不可达对象,回收内存。

有序销毁,比如不可达对象 X 引用了 A,那么应该在销毁 A 之前先销毁 X(有些垃圾回收算法并不能做到这一点)。

有些需求不容易被满足,比如 4,5,7,目前,还没有人满足以上需求的同时去除 GIL 成功的。

积重难返

这些年 Python 实在太火了,很多优秀的库都是基于 CPython 进行编写的,很多都是 90 年代的 C 扩展库,如果要除去 GIL,那么很多基于 GIL 编写的 C 扩展便无法使用,也就是去了 GIL,Python 生态有很多扩展或三方库者无法使用。

还有一个很明显的例子,Python 解释器不止有 CPython,还有用 Java 编写的 Python,.NET 实现的 IronPython,这些解释器完全没有 GIL,可是有多少人为它们编写扩展呢?

Python 之所以如此火爆,与它有着丰富的三方库开箱即用有着很大的关系,积重难返,去除 GIL 很困难。

为什么 Python3 一开始时不去除 GIL

Python3 在最开始时是有机会实现很多新功能,在此过程中,打破了一些现有的 C 扩展,然后需要更新和移植更改以配合 Python 3,这也是 Python3 一开始不被社区所接受的原因。

与 Python2 相比,删除 GIL 将使 Python3 在单线程性能方面更慢,如果 Python3 在单线程性能方面更慢,您可以想象 Python3 不可能有未来。因此,结果是 Python3 仍然有 GIL。

但 Python3 确实为现有的 GIL 带来了重大改进,在 Python 3.2 版本中,确保了计算密集型线程和 I/O 密集型线程并存时, I/O 密集型长期获取不到 GIL 的问题,提升了整体性能。

最后的话

Python 因为内存管理不是线程安全的,因此自出生起就自带 GIL,然后很多扩展都是在 GIL 的保护下编写的,时间一长积重难反,Python3 一开始也因去除 GIL 导致单线程性能下降的问题而保留 GIL,现在已经是 Python3.9 版本了,Python 已不可能再去除 GIL了,换句话说,去除 GIL 的 Python 也就不是我们认识的 Python 了。

不过不必沮丧,GIL 影响的也仅仅是多线程执行计算密集型的任务罢了,这种场景大多数程序员都极少遇到,即使有,可以使用多进程来避免 GIL 的影响,或者使用其他编程语言实现,任何编程语言都不是完善的,发挥所长是最重要的,即使慢,我也不在乎,也会依然使用 Python。

python为什么不解除gil_Python有可能去除GIL吗?相关推荐

  1. Python实践:CSDN图片水印批量去除

    Python实践:CSDN图片水印批量去除 背景 思路理清 Python代码 背景 在使用CSDN做图床时,经常遇到上传的大量图片被自动加上水印,十分影响阅读体验.网上大部分博客,都只是讲CSDN用m ...

  2. Python jieba分词如何添加自定义词和去除不需要长尾词

    Python jieba分词如何添加自定义词和去除不需要长尾词 作者:虚坏叔叔 博客:https://xuhss.com 早餐店不会开到晚上,想吃的人早就来了!

  3. GDAL+Python实现栅格影像处理之小斑块去除

    GDAL+Python实现栅格影像处理之小斑块去除 小斑块去除 使用方法 效果展示 小斑块去除 指定波段中小于指定像元个数的细小图斑清除,并且使用周围的像元值来替换. 使用方法 这里我们采用gdal. ...

  4. python 3.9 gil_Python进阶:深入GIL(下篇)

    Python进阶:深入GIL(下篇)HackPython致力于有趣有价值的编程教学 简介 有朋友吐槽,文章中太多表情,其实我加表情的初衷是避免大家阅读疲劳,既然造成了反效果,后面的内容就不会在添加表情 ...

  5. python删除指定位置的字符串_python去除区域 python删除字符串中指定位置字符

    python删除字符串中指定位置字符 原程序是这样的: ser = serial.Serial("/dev/ttyAMA0", 9600) def main字符串的话,你可以把他当 ...

  6. python 如何从列表中剔除(去除)重复元素?set()

    方法1:用内置函数set() 方法2:遍历去除元素 参考文章:python中如何去除列表中重复元素?

  7. python shell怎么换行_python shell:去除fasta文件的换行符

    导读 很多程序输出的fasta序列每60个碱基会换一次行,下面是一个去除碱基序列后的换行符的方法. 一.输入 cat test # 一个随便写的文件 >sequence_1 AAAA GGGG ...

  8. Python音频信号处理 2.使用谱减法去除音频底噪

    使用谱减法去除音频底噪 上一篇文章我主要分享了短时傅立叶变换及其逆变换在python中的实现,有兴趣的可以阅读一下该篇文章,地址如下: Python音频信号处理 1.短时傅里叶变换及其逆变换 那么在本 ...

  9. python遍历数组同时去掉括号_python去除括号

    广告关闭 腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元! t(1) ()既可以表示tuple,又可以作为括号表示运算时的优先级,结果 (1 ...

最新文章

  1. 2019年5月自律清单
  2. Python Django 数据缓存存储位置类
  3. python绘制相关性矩阵_python seaborn heatmap可视化相关性矩阵实例
  4. 关于C#关闭窗体后,依旧有后台进程在运行的解决方法
  5. 利用XML文件的一个写日志的类!!!!!
  6. 基于opencv的身份证识别系统
  7. mac录制视频——OBS
  8. GIS公司分布图GIS院校分布图
  9. 国内使用谷歌地图方案
  10. 大数据组件笔记 -- ZooKeeper
  11. teamviewer检测到商业用途的解决办法(win7 win8 win10亲测) 修改teamviewerID
  12. java判断工作日_java 查询指定月份的工作日(不包括法定节假日)
  13. C++ 单例模式学习(Singleton)
  14. 190亿像素的全世界最长全景照片
  15. 计算机中乘法是什么函数,excl中的乘法函数符号是什么
  16. 小微企业如何通过运营公众号提升业绩?
  17. Push rejected by evil dragon bureaucrats
  18. shell题库选择题_linux基础shell考试试卷习题.docx
  19. L1-059 敲笨钟(分数 20)
  20. 用 Kerberos 为 J2ME 应用程序上锁

热门文章

  1. 《Inside UE4》读书总结一
  2. 将低端文石电子书设备改造为电脑显示器的几次尝试
  3. flash builder增加flash设计效果
  4. Eclipse提交代码错误:rejected –non-fast-forward解决方法
  5. eclipse导入项目出现红色感叹号怎么办
  6. 山西高考成绩位次查询2021,2020年山西高考位次排名查询 山西高考位次所对应的学校...
  7. 计算机学院吉祥物意见征集,关于开展山西农业大学信息学院校园吉祥物作品征集活动的通知...
  8. 出现静止性震颤要注意!没准您已经患上帕金森
  9. selenium+Java处理JS弹窗
  10. SpringBoot--@InitBinder--使用/原理