围绕全局解释器锁(GIL)工作

为什么有 GIL?

自 1992 年 Python 线程开始以来,GIL 一直在 CPython 中出现。它旨在确保运行 python 代码的线程安全性。使用 GIL 编写的 Python 解释器可防止多个本机线程同时执行 Python 字节码。这使得插件可以轻松确保其代码是线程安全的:只需锁定 GIL,只有你的活动线程能够运行,因此你的代码自动是线程安全的。

简短版本:GIL 确保无论你拥有多少处理器和线程,一次只能运行一个 python 解释器的一个线程。

这有很多易用的好处,但也有很多负面的好处。

请注意,GIL 不是 Python 语言的要求。因此,你无法直接从标准 python 代码访问 GIL。并非所有 Python 实现都使用 GIL。

有 GIL 的解释器: CPython,PyPy,Cython(但你可以用 nogil 禁用 GIL)

没有 GIL 的译员: Jython,IronPython

有关 GIL 如何运作的详细信息:

当线程正在运行时,它会锁定 GIL。当线程想要运行时,它会请求 GIL,并等待它可用。在 CPython 中,在版本 3.2 之前,正在运行的线程将检查一定数量的 python 指令,以查看其他代码是否需要锁定(即,它释放了锁,然后再次请求它)。这种方法往往导致线程饥饿,主要是因为释放锁的线程会在等待线程有机会唤醒之前再次获取它。从 3.2 开始,希望 GIL 的线程等待锁定一段时间,之后,它们设置了一个共享变量,迫使正在运行的线程产生。但是,这仍然会导致执行时间大幅延长。有关详细信息,请参阅 dabeaz.com(参考部分)中的以下链接。

当线程执行 I / O 操作时,CPython 会自动释放 GIL。图像处理库和 numpy 数字运算操作在执行处理之前释放 GIL。

GIL 的好处

对于使用 GIL 的解释器,GIL 是系统性的。它用于保留应用程序的状态。好处包括:

  • 垃圾收集 - 在 GIL 锁定时必须修改线程安全引用计数。*在 CPython 中,所有的 garbarge 集合都与 GIL 相关联。*这是一个很大的问题; 请参阅有关 GIL 的 python.org wiki 文章(在下面的参考文献中列出),以获取有关如果想删除 GIL 必须仍然可用的内容的详细信息。
  • 易于处理 GIL 的程序员 - 锁定一切都很简单,但很容易编码
  • 简化从其他语言导入模块的过程

GIL 的后果

GIL 只允许一个线程在 python 解释器中一次运行 python 代码。这意味着运行严格 python 代码的进程的多线程不起作用。在针对 GIL 使用线程时,线程的性能可能比在单个线程中运行时差。

参考文献:

https://wiki.python.org/moin/GlobalInterpreterLock - 它的功能快速摘要,所有好处的详细信息

http://programmers.stackexchange.com/questions/186889/why-was-python-written-with-the-gil - 写得很清楚

http://www.dabeaz.com/python/UnderstandingGIL.pdf - GIL 如何工作以及为什么它会减慢多核心的速度

http://www.dabeaz.com/GIL/gilvis/index.html - 显示 GIL 如何锁定线程的数据的可视化

http://jeffknupp.com/blog/2012/03/31/pythons-hardest-problem/ - 简单易懂 GIL 问题的历史

https://jeffknupp.com/blog/2013/06/30/pythons-hardest-problem-revisited/ - 有关解决 GIL 限制的方法的详细信息