2009-08-18 126 views
145

什么是全局解释器锁,为什么它是一个问题?什么是全局解释器锁(GIL)?

大量的噪音,已经取得了从周围的Python去除GIL,我想知道为什么是如此的重要。我从来没有编写过编译器和解释器,所以不要因为细节而节俭,我可能需要他们去理解。

+0

可能重复的[Why the Global Interpreter Lock?](http://stackoverflow.com/questions/265687/why-the-global-interpreter-lock) – 2015-09-10 10:03:42

回答

144

Python的GIL旨在序列化来自不同线程的解释器内部的访问。在多核系统上,这意味着多线程无法有效利用多核。 (如果GIL没有导致这个问题,大多数人不会关心GIL--由于多核系统的普及程度越来越高,它只是被提出来作为一个问题。)如果你想详细了解它,您可以查看this video或查看this set of slides。这可能是信息太多了,但你没询问详情:-)

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

更新:更新后的视频链接指向Youtube,因为之前的blip.tv链接已经腐烂。

+31

好的答案 - 基本上,这意味着Python中的线程只适用于阻止I/O;你的应用程序永远不会超过1个处理器使用的CPU核心 – 2009-08-18 15:26:29

+5

“作为一名Python开发人员,除非你正在编写C扩展程序,否则通常不会遇到GIL” - 您可能不知道多线程的原因以蜗牛速度运行的代码是GIL,但你一定会感受到它的影响。令我惊讶的是,利用Python的32核心服务器意味着我需要32个进程以及所有相关的开销。 – Basic 2014-01-07 17:42:36

+5

@PaulBetts:这是不正确的。性能关键代码很可能已经使用了可以释放GIL的C扩展,例如'regex','lxml','numpy'模块。 Cython允许在自定义代码中释放GIL,例如['b2a_bin(data)'](https://gist.github.com/zed/3526111) – jfs 2015-08-16 13:34:10

41

假设你有多个线程这不真的触摸对方的数据。那些应该尽可能地独立执行。如果你有一个“全局锁定”,你需要获取以便(称)调用一个函数,这可能最终成为一个瓶颈。首先,您可以从多线程中获益不多。

为了把它变成一个真正的世界类比:假如100个开发者在一个公司只有一个咖啡杯的工作。大多数开发者会花时间等待咖啡而不是编码。

无的,这是Python特定的 - 我不知道什么样的Python需要GIL在首位的细节。不过,希望它给你一个更好的概念概念。

+0

但是,如果开发者在做票务支持,而不是(写作2 - 分钟回复,然后等待1小时),尽管只有一个咖啡杯,但他们都会很有成效。 – 2017-06-28 10:28:09

1

维基百科有一个全球性的解释的一个很好的说明锁

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

这个漂亮的文章,讨论在Python的GIL那篇文章的链接。

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

+0

可能最好链接到DDJ文章的开头部分 - http://www.ddj.com/linux-open-source/206103078 – 2009-08-18 15:02:19

+5

谢谢,但我在做这个问题之前做了功课,当然还是去了谷歌和维基百科第一。 – 2009-08-18 15:02:47

13

当两个线程可以访问相同的变量,你有问题。 在C++中,避免此问题的方法是定义一些互斥锁,以防止两个线程同时进入对象的setter。

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

这意味着,如果你开始为了充分利用你的多核处理器的写一些多线程代码,你的表现也不会提高。 通常的解决方法包括进行多进程。

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

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

的GIL问题仍然是有效的Python 3000

+0

Stackless仍然有一个GIL。 Stackless不会改进线程(如在模块中) - 它提供了一种不同的编程方法(协程),它尝试侧重解决问题,但需要非阻塞函数。 – jnoller 2009-08-18 16:24:02

+0

好点。感谢您的评论 – fulmicoton 2009-08-18 22:19:26

+0

3.2中的新GIL如何? – new123456 2011-07-07 01:11:56

7

Watch David Beazley告诉你所有你想知道的一切GIL。

+3

他是一位出色的谈话者 - 如果有人会说服你,GIL很糟糕,那就是他。 – new123456 2011-07-07 01:11:32

+1

链接已死亡。 :( – szeitlin 2015-05-11 17:09:53

+3

David Beazley - 了解Python GIL - https://www.youtube.com/watch?v=Obt-vMVdM8s – 2015-06-14 21:16:48

13

让我们先了解一下Python的GIL提供:

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

现在为什么是一个问题:

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

但是,潜在的阻塞或长时间运行的操作(例如I/O,图像处理和NumPy数字运算)发生在GIL之外。取自here。因此,对于这样的操作,尽管存在GIL,但多线程操作仍然比单线程操作更快。所以,GIL并不总是一个瓶颈。

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

+3

** Note **: PyPy有** GIL **。_参考:[http://doc.pypy.org/en/latest/faq.html#does-pypy-have-a-gil-why](http://doc.pypy .org/en/latest/faq.html#does-pypy-have-a-gil-why)。虽然Ironpython和Jython没有GIL。 – 2016-06-08 06:27:36

+0

确实,PyPy有一个GIL,但IronPython没有。 – Emmanuel 2018-01-17 14:47:48

0

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

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

在CPython中,全局解释锁,或GIL是一个互斥体,可以防止多个本地线程一次执行Python字节码。这个锁主要是因为CPython的内存管理不是线程安全的。

如何从Python中删除它?

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

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

1

我想分享本书多线程Visual Effects的示例。因此,这里是一个典型的死锁情况

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      ║ 
╚═══╩════════════════════════════════════════╩══════════════════════════════════════╝ 
4

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

有理由使用Python的线程包。如果你想同时运行一些东西,而且效率不是问题,那么它就非常好,很方便。或者如果你正在运行需要等待某些事情的代码(比如一些IO),那么它可能会很有意义。但线程库不会让你使用额外的CPU核心。多线程可以外包给操作系统(通过执行多处理),某些调用Python代码的外部应用程序(例如Spark或Hadoop)或一些代码(Python代码)(例如:你可以让你的Python代码调用一个执行昂贵的多线程的C函数)。