GIL

GIL (Global Interpreter Lock) 全局解释器锁 #

GIL 是一个全局互斥锁 mutex,它阻止多个线程同时执行Python字节码。 原因是 CPython 不是线程安全的。

某个线程想要执行,必须先拿到GIL,这样一来,不管任何时刻,只有一个线程在虚拟机中运行。

当一个线程取得 GIL 全局锁并开始执行字节码时,对已执行字节码进行计数。 当执行字节码达到一定数量或遇到IO操作,线程主动释放 GIL 全局锁并唤醒其他线程。

两种场景的影响 #

IO密集型 #

程序执行时大部分时间处于 IO Blocked 状态。

程序受 GIL 影响相对有限,因为线程在等待 IO 处理时可以让出 GIL 以便其他线程拿到虚拟机执行权。 一个多线程网络爬虫程序可以极大缩短程序运行时间。

计算密集型 #

程序执行时大部分时间处于 Running 状态。

程序受 GIL 影响很大,在 GIL 约束下,虚拟机只能交替执行不同的线程。

多核CPU并发 #

多进程+协程 #

python下想要充分利用多核CPU,就用多进程。

每个进程独立运行一个虚拟机,有各自独立的GIL,互不干扰,这样就可以真正意义上的并行执行。 所以在python中,多进程的执行效率优于多线程(仅仅针对多核CPU而言)

多进程+协程,既充分利用多核,又充分发挥协程的高效率,可获得极高的性能。

多核多线程 不能用 #

多核多线程比单核多线程差,原因是:

  • 单核下的多线程,每次释放GIL,唤醒的那个线程都能获取到GIL锁,所以能够无缝执行;
  • 多核下,CPU0 释放GIL后,其他CPU上的线程都会进行竞争, 但GIL可能会马上又被 CPU0 拿到,导致其他几个CPU上线程会醒着、等待、到进入待调度状态, 这样会造成线程颠簸,导致效率更低。