什么是GIL
首先根据字面意思就是 Global Interpreter Lock (全局解释器锁), 是Cpython虚拟机上用作多线程互斥的一种机制, 它的作用就是保证任何情况下, 虚拟机中只会有一个线程运行,而其它线程都处于等待GIL释放的状态。
GIL如何工作
这个就必须了解python的多线程机制, python的线程是操作系统的原生线程, linux 对应的是pthread, 全称是posix thread, Windows对应的是windows thread。 可以看出python的线程是用户态线程, 只不过不同操作系统的线程映射模式不同,即用户态线程与内核态的映射关系不同。
由于GIL的存在, 当某个线程A获得了GIL,执行了一些计算, 其他的线程只能等待A释放GIL之后才能获取GIL进入解释器执行计算。
这里python的线程必须主动释放GIL并挂起,这里有两种情形
1 check_interval调度
python里有个机制叫做check_interval,这里python模拟了操作系统切换进程的时钟中断模式,当一个进程执行了一段时间之后,发生了时钟中断,操作系统响应这种中断,并开始进行进程的调度。python还借用了底层操作系统所提供的线程调度机制来决定下一个进入python解释器的线程是谁。python只是做了线程调度中的其中的何时挂起线程的工作,至于下一个调度哪个线程是由操作系统来完成的。
不同的python版本,这个中断模式也有一定的差别。
我们都知道线程的执行其实就是一条条指令被执行,python2中维护了这么一个数值来统计指令的数目, 这个数目就相当于时钟,python2中将这个数值默认值设为100,我们也可以通过sys.setcheckinterval() 来调节这个数值。即当python中取得GIL的线程在执行完100条指令后就会被强制挂起并释放GIL,然后立即重新启动线程调度机制,来决定下一个进入python解释器的线程。
python3.2后这个interval变成了时间15毫秒,通过固定时间而不是指令数量来进行线程的强制切换。
2 阻塞调度
在线程A通过某种操作, 比如说等待输入,将自身阻塞后, 该线程将释放GIL,挂起自身,重新触发线程调度。
为什么存在GIL
在回答之前,先要明白这么一句话:
GIL的设计不是为了python应用层面的开发者,而是主要为了方便cpython解释器的编写者。
GIL并不能保证我们python使用者的线程安全。
所以作为python使用者, 我们需要使用锁来保证自己的线程安全。
主要有两个原因:
1 设计者为了规避类似内存管理这样的复杂竞争风险问题
2.cpython大量使用了C语言库,大部分C语言都不是线程安全的。因为线程安全会降低性能和增加复杂度。
GIL有什么特点
GIL 对程序中线程的影响足够简单,你可以在手背上写下这个原则:“一个线程运行 Python ,而其他 N 个睡眠或者等待 I/O.”
如何绕过GIL
通过多进程模式
采用c语言扩展
