关于 python 的全局解释器锁 GIL

关于 python 里的 GIL 简单说几句,GIL 全称 Global Interpreter Lock,引用官网的描述是这样的:

In CPython, the global interpreter lock, or GIL, is a mutex that protects access to Python objects, preventing multiple threads from executing Python bytecodes at once. This lock is necessary mainly because CPython's memory management is not thread-safe. (However, since the GIL exists, other features have grown to depend on the guarantees that it enforces.)

简单翻译 GIL 是一个用户访问 Python 对象的全局锁,用来阻止多个线程同时执行字符码,因为 CPython 解释器本身就不是线程安全的。因此,一个Python进程通常不能同时使用多个 CPU 核心。

这本身是 CPython 解释器的局限,与 Python 语言无关,相比而言 Jython 和 IronPython 就没有这种限制。

计算密集型

因为编写 Python 代码时无法控制 GIL,所以对于计算密集型应用是相当不友好的,在这种情况下最好的解决办法就是采用多进程,各个进程都有了自己的 GIL,互不干扰,这样就成了真正的并行执行了。

I/O 密集型

这个场景 GIL 基本是没啥影响的,Python 标准库中所有执行阻塞型 I/O 操作的函数,在等待操作系统返回结果时都会释放 GIL,允许其他线程运行。time.sleep()函数也会释放 GIL。因此,尽管有 GIL,Python 线程还是能在 I/O 密集型应用中发挥作用。

根据我们使用强类型语言的经验,比如C#和Java,我们肯定会疑惑Python中的字典是线程安全的吗? 答:是的,使用CPython,有GIL(全局锁机制),保证每个进程在同一时刻只有一个线程能运行,对资源进行操作,所以可以说Python中字典、序列等都是线程安全的。

版本差别

  1. 在 python2.x 里,GIL 的释放逻辑是当前线程遇见 IO 操作或者 ticks 计数达到 100 时进行释放。(ticks可以看作是 python 自身的一个计数器,专门做用于 GIL,每次释放后归零,这个计数可以通过 sys.setcheckinterval 来调整)。每次释放 GIL 锁,线程进行锁竞争、切换线程,会消耗资源。
  2. 在 python3.x 中,GIL 不使用 ticks 计数,改为使用计时器(执行时间达到阈值后,当前线程释放 GIL),这样对 CPU 密集型程序更加友好,但依然没有解决 GIL 导致的同一时间只能执行一个线程的问题,所以效率依然不尽如人意。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注