Skip to content

GIL 全局解释器锁

GIL -- global interpreter lock -- 全局解释器锁

1. GIL 是什么

CPython 是用 C 语言实现的 Python 解释器。作为官方实现,它是最广泛使用的 Python 解释器。除了 CPython 以外,还有用 Java 实现的 Jython,用 .NET 实现的 IronPython,使 Python 方便地和 Java 程序、.NET 程序集成。另外还有一些实验性的 Python 解释器比如 PyPy

GIL 是 CPython 解释器所采用的一种机制,它确保同一时刻只有一个线程在执行 Python bytecode(字节码,其解释看下文)。此机制通过设置对象模型(包括 dict 等重要内置类型)针对并发访问的隐式安全简化了 CPython 实现。给整个解释器加锁使得解释器多线程运行更方便,其代价则是牺牲了在多处理器上的并行性。

bytecode -- 字节码
Python 源代码会被编译为字节码,即 CPython 解释器中表示 Python 程序的内部代码。字节码还会缓存在 .pyc 文件中,这样第二次执行同一文件时速度更快(可以免去将源码重新编译为字节码)。这种 "中间语言" 运行在根据字节码执行相应机器码的 virtual machine 之上。请注意不同 Python 虚拟机上的字节码不一定通用,也不一定能在不同 Python 版本上兼容。

2. GIL 为什么存在

GIL 的存在更多的是历史原因。早期 CPython 都是基于在单核 CPU 的前提下设计的,没考虑过多核的情况。

2.1 GIL 的好处

  1. 提高单线程程序的速度。
  2. 轻松集成通常不是线程安全的 C 库。(C 扩展更容易)
  3. 对于 IO 密集型程序,它在多线程情况下更快。

2.2 为什么使用 GIL

  1. 在 CPython 中,全局解释器锁或 GIL 是一个互斥锁,可防止多个本机线程同时执行 Python 字节码。这个锁是必要的,主要是因为 CPython 的内存管理不是线程安全的。
  2. GIL 是有争议的,因为它阻止了多线程 CPython 程序在某些情况下充分利用多处理器系统。请注意,潜在的阻塞或长时间运行的操作(例如 I/O、图像处理和 NumPy 数字运算)发生在 GIL 之外。因此,只有在 GIL 中花费大量时间来解释 CPython 字节码的多线程程序中,GIL 才会成为瓶颈。

2.3 GIL 的影响

  1. 当且仅当您在纯 Python 中执行 CPU 密集型工作时,GIL 才是一个问题。
  2. 无法发挥现在 CPU 的多核优势。

3. 做了哪些优化

一些扩展模块,无论是标准的还是第三方的,都被设计成在执行压缩或散列等计算密集型任务时释放 GIL。 此外,在执行 I/O 时总是释放 GIL。

创建一个(以更精细粒度来锁定共享数据的)“自由线程”解释器的努力从未获得成功,因为这会牺牲在普通单处理器情况下的性能。据信克服这种性能问题的措施将导致实现变得更复杂,从而更难以维护。

4. 总结

  1. IO 密集型任务场景,可以使用多线程可以提高运行效率
  2. CPU 密集型任务场景,不要使用多线程,而是使用多进程

参考