Python速度慢的头号嫌疑犯——GIL

Python速度慢的两大原因

相比于C/C++/JAVA,python确实比较慢,在一些特殊场景下,Python比C++慢100~200倍。
由于Python速度慢,很多公司的基础架构代码依然使用C++开发。比如现在各个互联网大厂,阿里/腾讯/等的推荐引擎、搜索引擎、存储引擎等底层对性能要求高的模块。

原因一

python是动态类型语言,是边解释边执行的,即解释型语言。

解释型语言,是在运行的时候将程序翻译成机器语言。解释型语言的程序不需要在运行前编译,在运行程序的时候才翻译,专门的解释器负责在每个语句执行的时候解释程序代码。这样解释型语言每执行一次就要翻译一次,效率比较低。

我们知道C/C++程序在执行前会有一个编译的过程,将程序编译成机器码再进行执行,而python并没有这个过程。另外,python中的变量既可以是数字也可以是字符串。但是这也导致了新的问题,也就是python需要随时检查变量类型,这也是造成python速度慢的原因。

原因二

GIL,使得Python无法利用多核CPU并发执行。
我们可以先用一个直观的例子来感受一下GIL在Python多线程程序运行的影响

import time
start = time.clock()
def CountDown(n):
    while n >0:
        n-=1
CountDown(100000)
print("Time used",(time.clock()-start))

运行结果

Time used 0.0051301

在我们以往的印象中,使用多个线程是可以加快程序运行效率的,因此我们使用两个线程来试试

import time
from threading import Thread
start = time.clock()
def CountDown(n):
    while n>0:
        n-=1
t1 = Thread(target=CountDown,args=[100000//2])
t2 = Thread(target=CountDown,args=[100000//2])
t1.start()
t2.start()
t1.join()
t2.join()
print("Time used",(time.clock()-start))

运行结果:

Time used 0.006331900000000001

可以看到,两个线程非但没有提高效率,反而还降低了。这就是GIL带来的后果。

什么是GIL

它叫做全局解释器锁(英文名:Global Interpreter Lock,缩写为GIL)。是计算机程序设计语言解释器(这里说就是Python解释器CPython了)用于同步线程的一种机制,它使得任何时刻仅有一个线程在执行。即使在多核处理器上,使用GIL的解释器也只允许同一时间执行一个线程。
我们来看下面这张图,图片来源:http://www.dabeaz.com/python/UnderstandingGIL.pdf
在这里插入图片描述
下面这条文字的意思是当线程执行的时候,它持有GIL,当遇到IO的时候,它释放了GIL。
图中有三个线程,thread1执行时,它持有GIL,当它遇到IO时,此时thread2才能执行,当thread2遇到IO时,它会释放GIL,thread3才能执行。以此循环。
也就是说,虽然我们启动了三个线程,但是从图中看,同一时间还是只有一个线程在运行。
由于GIL的存在,即使电脑有多核CPU,单个时刻也只能使用1个,相比并发加速的C++/JAVA所以慢。

为什么会有GIL这个东西

其实简言之:Python的设计初期,是为了规避并发问题引入的GIL,现在想去除却去不掉了。Python在有些版本中试图去除掉GIL,但是发现性能比原来还下降了,所以可以认为这是一个缺陷,但短期内不能修复。

其实GIL最初是为了解决多线程之间数据完整性和状态同步问题,这里对原因做一下详解:

Python中对象的管理是通过引用计数器进行的,引用为0则释放对象。

我们来看一个例子:
开始,线程A和线程B都引用了对象obj,此时obj.ref_num = 2,线程A和线程B都想撤销对obj的引用,如果没有GIL会发生什么
在这里插入图片描述
通过上图,我们可以很清楚的看到多线程之间数据完整性和同步性的问题,如果不加锁的话,会导致Python引用计数器的功能发生混乱。
为了解决此类问题,引入GIL,Python在此基础上进行了封装。

怎么样规避GIL带来的限制?

用于IO密集型计算

对于多线程threading机制依然是有用的,可以用于IO密集型计算。
因为在IO(read,write,send,recv,etc)期间,线程会释放GIL,实现CPU和IO的并行,因此,多线程用于IO密集型计算依然可以大幅度提示速度。
但是,多线程用于CPU密集型计算时,只会更加拖慢速度。

使用multiprocessing

为了应对GIL带来的问题,Python提供了multiprocessing模块,它可以利用多进程机制实现并行计算、利用多核CPU的优势

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

降温vae+

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值