Python培训
400-996-5531
我们知道,在CPython中,有一个全局解释器锁,英文叫globalinterpreterlock,简称GIL,是一个互斥锁,用来保护Python世界里的对象,防止同一时刻多个线程执行Python的字节码,从而确保线程安全,这导致了Python的线程无法利用多核CPU的优势,因此有人说Python的多线程是伪多线程,性能不高,那么Python将来有可能去除GIL吗?
要回答这个问题,先从GIL的起源进行分析。
一、GIL的起源
Python第一次发布是在1991年,当时的CPU都是单核,单核中,多线程主要为了一边做IO,一边做CPU计算而设计的,Python编译器是由C语言编写的,因此也叫CPython,那时候很多编程语言没有自动内存管理的功能,为了实现自动垃圾回收,Python为每一个对象进行了引用计数,当引用计数为0的时候说明该对象可以回收,从而释放内存了,比如:
>>>importsys>>>data={'gzh':'Python七号'}>>>var1=data>>>sys.getrefcount(data)3>>>
这里data对象就有3个引用,一个是本身,一个是变量var1,一个是getrefcount函数的参数,如果此时又有一个线程引用了data,那么引用计数再增加1,如果某个线程使用了data后运行结束,那么引用计数就减少1,多线程对同一个变量「引用计数」进行修改,就会遇到raceconditions(竞争),为了避免raceconditions,最简单有效的办法就是加一个互斥锁。
如果对每一个对象都加锁,有可能引发另一个问题,就是死锁,而且频繁的获取和释放会导致性能下降,最简单有效的方法就是加一个解释器锁,线程在执行任何字节码时都先获取解释器锁,这就避免了死锁,而且不会有太多的性能消耗。当时CPU都是单核,而且这种GIL设计简单,并不会影响性能,因此一直沿用至今天。GIL存在最主要的原因,就是因为Python的内存管理不是线程安全的,这就是GIL产生并存在的主要缘由。
二、尝试消除GIL
CPU进入多核时代后,可以同时做多个计算任务,GIL才真正变成问题。在1999年,有个叫GregStein的大佬基于Python1.5版本消除了GIL,取代代之的是在可变数据结构上加上更细粒度的锁,也提交了补丁用于去除对全局可变对象的依赖,然后在标准测试时表明去除GIL后单线程比不去除时慢了近2倍,测试的机器还是当时性能最好Windows机器。也就是说除去了GIL后,你使用2个CPU才能获取比原来1个CPU稍微好一点的性能,这种提升明显得不偿失,GregStein的尝试也就失败告终。
Python之父GuidovanRossum也欢迎社区的志愿者去尝试去除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扩展,然后需要更新和移植更改以配合Python3,这也是Python3一开始不被社区所接受的原因。
与Python2相比,删除GIL将使Python3在单线程性能方面更慢,而且很多优秀的扩展将不能再使用,如果真的这样,可以想象Python3不可能有未来,最终的结果是Python3仍然保持有GIL。
但Python3也为现有的GIL带来了重大改进,在Python3.2版本中,确保了计算密集型线程和I/O密集型线程并存时,I/O密集型长期获取不到GIL而无法执行的问题,提升了多线程的性能。
五、最后的话
Python因为内存管理不是线程安全的,因此自出生起就自带GIL,然后很多扩展都是在GIL的保护下编写的,时间一长积重难反,Python3一开始也因去除GIL导致单线程性能下降的问题而保留GIL,现在已经是Python3.9版本了,将来Python去除GIL的可能性微乎其微,换句话说,去除GIL的Python也就不是我们认识的Python了。
不过不必沮丧,GIL影响的也仅仅是多线程执行计算密集型的任务罢了,这种场景大多数程序员都很少遇到,即使有,可以使用多进程来避免GIL的影响,或者使用其他编程语言实现,任何编程语言或技术都不是十全十美的,发挥所长是最重要的,即使有GIL,我也不在乎,也会依然使用Python。
免责声明:内容来源于公开网络,若涉及侵权联系尽快删除!
填写下面表单即可预约申请免费试听! 怕学不会?助教全程陪读,随时解惑!担心就业?一地学习,可全国推荐就业!
Copyright © 京ICP备08000853号-56 京公网安备 11010802029508号 达内时代科技集团有限公司 版权所有
Tedu.cn All Rights Reserved