浅谈Python多线程之GIL

Python学习中,我们完成多任务时,往往会使用多线程技术,那我们一定要知道GIL这个概念,GIL到底是做什么的?为什么要用GIL?它有哪些缺点?

什么是GIL

GIL即全局解释器锁(global interpreter lock),每个线程在执行前都需要先获取GIL,保证同一时刻只有一个线程可以执行,别的线程不能干扰当前线程的执行,只能在占有GIL锁的线程执行完之后再获取锁。

为什么要用GIL

为了更有效的利用多核处理器的性能,出现了多线程的编程方式,而随之带来的问题就是如何保证各个线程间数据一致性和状态同步。解决多线程之间数据完整性和状态同步的最简单方法自然就是加锁。CPython就设计了GIL这把全局锁来试图解决线程安全。但是它存在一些问题我们下面说明。

Note:CPython是特指用C语言实现的Python,即Python。Python还有一些其它的实现,比如Jython,是Java版的Python,还有PyPy,使用Python再实现的Python。各个解释器的详细信息读者可以自行百度。

GIL存在哪些问题

Python的线程,的确是封装的底层的操作系统的线程,也受到操作系统管理,但是,由于解释器的C语言实现部分在完全并行执行时并不能保证线程安全的。因此,解释器被GIL保护着,能确保任何时候都只能一个Python线程执行。
正因如此,GIL锁不能容忍一个线程一直占用资源,他会轮流执行python的其他线程,导致同一时刻只有一个线程使用CPU,也就是说多线程并不是真正意义上的同时执行,由于CPU执行速度够快从而达到了一种“伪多线程”的效果。

#测试多线程执行耗时--0.006826
from threading import Thread
 ​
def test_multi(n):
     t1 = Thread(target=test, args=(n // 2,))
     t2 = Thread(target=Decrement, args=(n // 2,))
     t1.start()
     t2.start()
     t1.join()
     t2.join()
test_multi(1000000)
#测试正常执行耗时--0.007235
def test(n):
     while n > 0:
         n -= 1
test(1000000)

我们发现,多线程与单线程的版本所运算的时间并没有想象中的提升很大。

而且,GIL也并不一定能够保证线程安全。虽然说Python有了GIL来锁住线程,但是并不意味着编写Python的程序的时候就不需要去注重线程安全了,因为有check_interval机制,还是会导致线程安全的问题。
check_interval这个机制在python2中和python3中是不一样的:

  • python2: 执行时钟的100ticks(对应1000个bytecodes)去释放这个锁
  • python3: 执行5ms,然后释放

而哪怕是一句简单的num+=n也是由多条bytecode组成,这些字节码执行到中间的时候可能会因为锁被剥夺而被打断,就会导致一条语句没有执行完,从而导致一致性被破坏。

所以也不能因为GIL就完全不注重race condition问题,使用Python多线程还是要加锁,threading模块的lock()方法,这样结果就不会出现差错了。实例化threading.Thread和继承threading.Thread这两种方式可以实现Python多线程,通过实例化的方式使用起来比较简单,使用继承的方式更加具有封装性。或者也可以使用封装好的一些工具类或者第三方模块。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值