GIL
有 Python 开发经验的人也许听说过这样一句话:Python 不能充分利用 CPU 的多核优势。
为什么呢?
因为Python(Cpython) 中存在 GIL,即global interpreter lock(全局解释器锁)。用于限制一个进程中同一时刻只有一个线程被CPU调度。Python 程序尽管也支持多线程,但由于受到 GIL 的保护,所以同一时刻,只有一条线程可以向前执行。
接下来我们详细谈谈 Python 中存在的 GIL。
标准的 Python 实现叫做 CPython。CPython 分两步来运行 Python 程序。
- 把文本形式的源代码解析并编译成字节码。
- 用一种基于栈的解释器来运行这份字节码。
执行 Python 程序时,字节码解释器必须保持协调一致的状态。那么怎么才能够保持协调一致的状态呢?
Python 采用 GIL 机制来确保这种协调性。
GIL 实际就是一把互斥锁,用以防止 CPython 受到占先(抢占)式多线程切换操作的干扰。所谓占先式多线程切换,是指某个线程可以通过打断另外一个线程的方式,来获取程序控制权。
假如这种干扰操作的执行时机不恰当,那就会破坏解释器的状态。
正是因为存在 GIL,那么这些干扰操作就不会发生了。GIL 可以保证每条字节码指令能够正确的与 CPython 实现及其 C 语言扩展模块协同运作。
既然 Python 不能充分利用 CPU 的多核优势,那么为什么还要支持多线程呢?
这是因为:
① 多线程使得程序看上去好像能够在同一时间做许多事情。
借助多线程,则能够令 Python 程序自动以一种看似平行的方式来执行线程调用的函数。这是因为 CPython 在执行 Python 线程的时候,可以保证一定程度的公平,但不是绝对的公平。由于受到 GIL 的限制,所以统一时刻实际上只能有一个线程得到执行。
② 在处理阻塞式的 I/O 操作,Python 在执行某些系统调用时,会触发多线程操作。
我们知道读写文件、在网络间通信、以及与显示器等设备相交互等,都属于阻塞式的 I/O 操作。为了响应这种阻塞式的请求,操作系统必须花一些时间,开发者可以借助多线程,把 Python 程序与这些耗时的 I/O 操作隔离开。
尽管受制于 GIL,但是用多个 Python 线程来执行系统调用的时候,这些系统调用可以可以平行的执行。GIL 虽然使得 Python代码无法并行,但它对系统调用却没有任何负面影响。
互斥锁
明白了 GIL 机制之后,也许你会认为在编写Python 代码时,是不是就不需要再使用互斥锁了?
NO !
实际上 GIL 并不会保护开发者自己编写的代码。这是因为同一时刻固然只能有一个 Python 线程得到执行,但是,当这个线程正在操作某个数据结构的时候,其他线程还是可能会打断它,一旦发生这种现象,就会破坏程序的状态,从而使相关的数据结构无法保持其一致性。为了保证所有线程能够得到公平地执行,Python 解释器会给每个线程分配大致相等的处理器时间。为了达到这样的分配策略,Python 系统可能当某个线程正在执行的时候将其暂停,然后使另一个线程继续往下执行。由于我们无法提前获知 Python 系统会在何时暂停这些线程,所以我们无法控制程序中某些操作是原子操作。
为了防止线程中出现数据(共享资源)竞争的行为,使开发者可以保护自己的数据结构不受破坏,Python 在 threading 模块中提供了最简单、最有用的工具:Lock 类,该类相当于互斥锁。
在开发中我们可以使用互斥锁来保护某个对象,使得在多线程同时访问某个对象的时候,不会将该对象破坏。因为同一时刻,只有一个线程能够获得这把锁。也就是说对将要访问的对象进行隔离,那么使用线程隔离的意义在于:是当前线程能够正确的引用到它自己创造的对象,而不是引用到其它线程锁创建的对象。
讲到这里你应该明白:在 Python 开发中多线程不在是鸡肋的原因了。
注意:
为什么gil没有被删除?因为删了gil会使得Python3单线程任务方面比Python2慢。
每个Python进程都有自己的Python解释器和内存空间,所以gil不会是问题(可以采用多进程代替多线程)。
替换Python解释器,gil只存在于cpython中。
在处理科学计算这类要持续使用CPU的任务时,单线程会比较快。
处理io操作等引起阻塞这类任务时,多线程会比单线程快。
锁的好处,确保了某段代码只能由一个线程从头到尾的完整执行。
锁的坏处, 阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行。效率大大降低。由于可以存在多个锁,不同的线程持有不同的锁,并试图获取对方持有的锁就会造成死锁。
多线程程序的执行顺序是不确定的。
总结:
GIL: 保证某时刻某进程中只有一个线程被执行。
互斥锁:保证共享资源的一致性(如经典的全局变量多线程操作时的数据安全性)