GIL全局解释器锁
1. 什么是GIL
GIL的全称是 Global Interpreter Lock,全局解释器锁。之所以叫这个名字,是因为Python的执行依赖于解释器。Python最初的设计理念在于,为了解决多线程之间数据完整性和状态同步的问题,设计为在任意时刻只有一个线程在解释器中运行。而当执行多线程程序时,由GIL来控制同一时刻只有一个线程能够运行。即Python中的多线程是表面多线程,也可以理解为fake多线程,不是真正的多线程。
2. GIL的优点与缺点
GIL的优点是显而易见的,GIL可以保证在多线程编程时,无需考虑多线程之间数据完整性和状态同步的问题。
GIL缺点是:多线程程序执行起来是“并发”,而不是“并行”。因此执行效率会很低,会不如单线程的执行效率。
网上很多人都提到过这样的疑问:”为什么我多线程Python程序运行得比其只有一个线程的时候还要慢?“显然,大家觉得一个具有两个线程的程序要比其只有一个线程时要快。事实上,这个问题是确实存在的,原因在于GIL的存在使得Python多线程程序的执行效率甚至比不上单线程的执行效率。很简单,由于GIL使得同一时刻只有一个线程在运行程序,再加上切换线程和竞争GIL带来的开销,显然Python多线程的执行效率就比不上单线程的执行效率了。
Python解释器的实现是有多个版本的:CPython, Jpython等。
CPython就是用C语言实现Python解释器,JPython是用Java实现Python解释器。那么 GIL的问题实际上是存在于CPython中的。GIL的问题得不到解决,一方面是因为CPython中一开始就使用GIL的设计理念,并且很多Package依赖于CPython甚至依赖于GIL。因此造成尾大不掉,实际上是个历史问题。
3. 如何规避GIL带来的影响
用multiprocess(多进程)替代Thread(推荐)
multiprocess库的出现很大程度上是为了弥补thread库因为GIL而低效的缺陷。它完整的复制了一套thread所提供的接口方便迁移。唯一的不同就是它使用了多进程而不是多线程。每个进程有自己的独立的GIL,因此也不会出现进程之间的GIL争抢。
当然multiprocess也不是万能良药。它的引入会增加程序实现时线程间数据通讯和同步的困难。就拿计数器来举例子,如果我们要多个线程累加同一个变量,对于thread来说,申明一个global变量,用thread.Lock的context包裹住三行就搞定了。而multiprocess由于进程之间无法看到对方的数据,只能通过在主线程申明一个Queue,put再get或者用share memory的方法。这个额外的实现成本使得本来就非常痛苦的多线程程序编码,变得更加痛苦了。
浙公网安备 33010602011771号