什么是全球解释器锁(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最好的解释。 请阅读。
这里有一篇长篇文章,谈论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工作)。
以下是一些演示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 ║ ╚═══╩════════════════════════════════════════╩══════════════════════════════════════╝