什么是全球解释器锁(GIL)?

什么是全球翻译锁,为什么这是一个问题?

从Python中删除GIL已经产生了很多噪音,我想知道为什么这么重要。 我从来没有写过编译器也没有自己的解释器,所以不要吝惜细节,我可能需要他们来理解。

Python的GIL旨在序列化来自不同线程的解释器内部的访问。 在多核系统上,这意味着多个线程不能有效地利用多个核心。 (如果GIL没有导致这个问题,大多数人都不会关心GIL,因为多核系统的普及程度越来越高,这只是一个问题。)如果你想详细了解它,您可以查看此video或查看这组幻灯片 。 这可能是太多的信息,但是你确实要求的细节:-)

请注意,Python的GIL只是参考实现CPython的一个问题。 Jython和IronPython没有GIL。 作为Python开发人员,除非要编写C扩展,否则通常不会遇到GIL。 C扩展编写者需要在扩展阻塞I / O时释放GIL,这样Python进程中的其他线程才有机会运行。

更新:更新指向video的链接指向Youtube,因为早先的blip.tv链接已经烂blip.tv了。

假设你有多个线程不能真正触及彼此的数据。 那些应该尽可能地独立执行。 如果你有一个“全局锁”,你需要获得一个函数,那么最终可能会成为瓶颈。 首先,你可以从multithreading中得到好处。

把它变成一个现实世界的比喻:想象一下在一家公司工作的100个开发人员只有一个咖啡杯。 大多数开发者会花时间等待咖啡而不是编码。

这些都不是Python特有的 – 我不知道Python首先需要一个GIL的细节。 不过,希望给你一个更好的概念概念。

只要有两个线程访问相同的variables,就有问题。 以C ++为例,避免这个问题的方法是定义一些互斥锁,以防止两个线程同时进入一个对象的setter。

在python中可以使用multithreading,但是两个线程不能同时以比一个python指令细的粒度执行。 正在运行的线程正在获取一个名为GIL的全局锁。

这意味着,如果您开始编写一些multithreading代码以利用多核处理器,则性能不会提高。 通常的解决方法包括进行多进程。

请注意,如果您使用C语言编写的方法,则可以释放GIL。

GIL的使用不是Python固有的,而是其一些解释器,包括最常见的CPython。 (#edited,看评论)

GIL问题在Python 3000中仍然有效。

我们先来了解python GIL提供的内容:

任何操作/指令都在解释器中执行。 GIL确保解释器在特定的时间由单个线程保持。 而你的multithreadingPython程序工作在一个单一的解释器。 在任何特定的时刻,这个解释器都由一个单独的线程来保存。 这意味着只有拿着解释器的线程在任何时刻都在运行

现在为什么是这个问题:

你的机器可能有多个核心/处理器。 多核心允许多个线程同时执行即多个线程可以在任何特定的时刻执行 。 但是由于解释器是由一个线程来保存的,其他线程即使可以访问一个内核也不会做任何事情。 所以,你没有获得多核心提供的任何优势,因为在任何时候,只有一个核心,这是当前持有解释器的线程正在使用的核心正在被使用。 所以,你的程序将需要很长的时间来执行,就好像它是一个单线程程序一样。

但是,潜在的阻塞或长时间运行的操作(如I / O,image processing和NumPy数字处理)在GIL之外发生。 从这里采取。 所以对于这样的操作,尽pipe存在GIL,multithreading操作仍然比单线程操作更快。 所以,GIL并不总是一个瓶颈。

编辑:GIL是CPython的实现细节。 PyPy和Jython没有GIL,所以一个真正的multithreading程序应该是可能的,认为我从来没有使用过PyPy和Jython,并且不确定这一点。

观看David Beazley告诉你一切你想知道的GIL。

我觉得这是GIL最好的解释。 请阅读。

python/UnderstandingGIL.pdf

这里有一篇长篇文章,谈论GIL和Python中的线程,我之前写过。 它有相当多的细节:

http://jessenoller.com/2009/02/01/python-threads-and-the-global-interpreter-lock/

Python不允许真正意义上的multithreading。 它有一个multithreading包,但如果你想multithreading来加快你的代码,那么通常不是一个好主意。 Python有一个叫做Global Interpreter Lock(GIL)的构造。 GIL确保只有一个“线程”可以在任何时候执行。 一个线程获取GIL,做一些工作,然后将GIL传递到下一个线程。 这种情况发生得非常快,所以在人眼看来,它们可能看起来像你的线程并行执行,但它们只是轮stream使用相同的CPU内核。 所有这些GIL通过增加执行的开销。 这意味着如果你想使你的代码运行得更快,那么使用线程包通常不是一个好主意。

有理由使用Python的线程包。 如果你想同时运行一些东西,而且效率不是问题,那么这是完全的,方便的。 或者如果你正在运行需要等待某些东西的代码(比如一些IO),那么它可能会很有意义。 但线程库不会让你使用额外的CPU核心。

multithreading可以外包给操作系统(通过多处理),一些调用你的Python代码的外部应用程序(例如Spark或Hadoop),或者你的Python代码调用的一些代码(例如:你可以让你的Python代码调用一个C函数来完成昂贵的multithreading工作)。

维基百科对全局解释器锁有很好的描述

http://en.wikipedia.org/wiki/Global_Interpreter_Lock

那篇文章链接了讨论Python中GIL的好文章。

http://www.ddj.com/linux-open-source/206103078?pgno=2

以下是一些演示GIL效果的代码: https : //github.com/cankav/python_gil_demonstration

为什么Python(CPython和其他)使用GIL

http://wiki.python.org/moin/GlobalInterpreterLock

在CPython中,全局解释器锁(GIL)是一个互斥锁,可以阻止多个本地线程同时执行Python字节码。 这个锁主要是因为CPython的内存pipe理不是线程安全的。

如何从Python中删除它?

像Lua一样,也许Python可以启动多个虚拟机,但python不这样做,我想应该有其他一些原因。

在Numpy或其他一些python扩展库中,有时把GIL释放到其他线程可以提高整个程序的效率。

我想分享一个来自Visual Effectsmultithreading的例子。 所以这是一个经典的死锁情况

 static void MyCallback(const Context &context){ Auto<Lock> lock(GetMyMutexFromContext(context)); ... EvalMyPythonString(str); //A function that takes the GIL ... } 

现在考虑序列中的事件导致死锁。

 ╔═══╦════════════════════════════════════════╦══════════════════════════════════════╗ ║ ║ Main Thread ║ Other Thread ║ ╠═══╬════════════════════════════════════════╬══════════════════════════════════════╣ ║ 1 ║ Python Command acquires GIL ║ Work started ║ ║ 2 ║ Computation requested ║ MyCallback runs and acquires MyMutex ║ ║ 3 ║ ║ MyCallback now waits for GIL ║ ║ 4 ║ MyCallback runs and waits for MyMutex ║ waiting for GIL ║ ╚═══╩════════════════════════════════════════╩══════════════════════════════════════╝