全局解释器锁(GIL)似乎经常被认为是Python中线程之类的操作比较棘手的主要原因-这就提出了一个问题:“为什么首先要这样做?”

不是程序员,我不知道为什么会这样-放入GIL背后的逻辑是什么?

评论

Wikipedia文章指出:“ GIL可能成为并行性的重要障碍,因为具有这种语言的动态性需要付出一定的代价”,并继续说:“采用这种锁定的原因包括:单线程程序速度的提高(无需分别获取或释放所有数据结构上的锁),并且易于集成通常不是线程安全的C库。“

@RobertHarvey,活力与它无关。问题是突变。

stackoverflow.com/questions/265687 / ...

忍不住感觉像Java缺少无符号数字一样,它的目的是防止不知道自己在做什么的人用脚射击。不幸的是,任何知道自己在做什么的人都会遇到一种语言不足的情况,这真是太可惜了,因为Python可以通过许多其他方式动摇

@Basic必须有某种标准的方法来处理Java中的字节数组(我已经很长时间没有使用过)了,以便进行加密数学运算。 Python(例如)没有带符号的数字,但是我什至不尝试使用它进行按位运算,因为有更好的方法。

#1 楼

Python有多种实现,例如CPython,IronPython,RPython等。

其中一些具有GIL,而有些则没有。例如,CPython具有GIL:

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

用GIL编程语言编写的应用程序可以设计为使用单独的进程来实现完全并行性,因为每个进程都有自己的解释器,进而有自己的GIL。

GIL的优点


提高了单线程程序的速度。
容易集成通常不是线程安全的C库。

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


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



在CPython中,全局解释器锁(即GIL)是一个互斥体,可以防止多个本机线程一次执行Python字节码。此锁之所以必要,主要是因为CPython的内存管理不是线程安全的。

GIL颇有争议,因为它阻止了多线程CPython程序在某些情况下充分利用多处理器系统。请注意,潜在的阻塞或长时间运行的操作(例如I / O,图像处理和NumPy数字运算)发生在GIL之外。因此,只有在GIL内部花费大量时间来解释CPython字节码的多线程程序中,GIL才成为瓶颈。


来自http://www.grouplens.org/node/244


Python具有GIL,而不是针对几个原因:


在单线程情况下速度更快。
在多线程情况下,I / O绑定程序速度更快。
它对于在C库中完成计算密集型工作的cpu绑定程序,在多线程情况下速度更快。
它使C扩展的编写更加容易:除了允许的地方(即在Py_BEGIN_ALLOW_THREADS和Py_END_ALLOW_THREADS宏之间)之外,没有任何Python线程切换。
它使包装C库更容易。您不必担心线程安全性。如果该库不是线程安全的,则只需在调用GIL时将其锁定即可。

C扩展可以释放GIL。 Python的标准库在每个阻塞的I / O调用周围释放了GIL。因此,GIL对I / O绑定服务器的性能没有影响。因此,您可以使用进程(分支),线程或异步I / O在Python中创建网络服务器,而GIL不会妨碍您。

C或Fortran中的数字库可以类似地用GIL发布了。当您的C扩展等待FFT完成时,解释器将执行其他Python线程。因此,在这种情况下,GIL也比细粒度锁定更容易和更快。这构成了大量的数字工作。 NumPy扩展会在可能的情况下释放GIL。

线程通常是编写大多数服务器程序的一种不好的方法。如果负载较低,则分叉会更容易。如果负载很高,则异步I / O和事件驱动的编程(例如使用Python的Twisted框架)会更好。使用线程的唯一借口是Windows上缺少os.fork。

仅当您在纯Python中执行CPU密集型工作时,GIL才是问题。在这里,您可以使用流程和消息传递(例如mpi4py)来获得更简洁的设计。 Python奶酪店中还有一个“处理”模块,该模块为进程提供与线程相同的接口(即,将threading.Thread替换为processing.Process)。

线程可用于维持程序的响应性。 GUI不管GIL。如果GIL损害了您的性能(请参见上面的讨论),则可以让您的线程产生一个进程并等待其完成。

评论


对我来说听起来像酸葡萄。 Python无法正确处理线程,因此您要弄清不必要或什至坏线程的原因。 “如果负载很低,分叉就容易了”,认真吗?仅在您坚持使用引用计数GC的情况下,GIL才能在所有这些情况下“更快”。

–迈克尔·伯格沃德(Michael Borgwardt)
13年2月13日在9:38



s / RPython / PyPy / g。 @MichaelBorgwardt给出原因,专业GIL是问题的重点,不是吗?尽管我同意这个答案的某些内容(即替代方案的讨论)不重要。不管是好是坏,现在几乎都无法消除重新计数-它在整个API和代码库中根深蒂固;如果不重写一半的代码并破坏所有外部代码,几乎要摆脱它。

–user7043
13年2月13日在13:35



不要忘记多处理库-从2.6开始的标准。对于某些简单类型的并行机制,它的工作池是一个非常漂亮的抽象。

– Sean McSomething
13年2月13日在18:52

@alcalde仅当您不知道自己在做什么和/或不希望自己的线程能够协同工作/进行通信时。否则,这将在后台造成很大的痛苦,特别是考虑到在某些OS上启动新进程的开销。我们有32个核心的服务器,因此要在CPython中充分利用它们,我需要32个进程。这不是一个“好的解决方案”,而是解决CPython的不足之处的一种方法。

–基本
2015年10月6日在21:40



在Windows以外的平台上存在线程的事实应足以证明,在每种情况下分支都不足够。

–zneak
2015年10月14日在18:55



#2 楼

首先,Python没有GIL。 Python是一种编程语言。编程语言是一组抽象的数学规则和限制。 Python语言规范中没有任何内容表明必须有一个GIL。

Python有许多不同的实现。有些拥有GIL,有些则没有。

拥有GIL的一个简单解释是编写并发代码很困难。通过在代码周围放置一个巨大的锁,可以强制其始终串行运行。问题解决了!

特别是在CPython中,一个重要的目标是使使用C语言编写的插件扩展解释器变得容易。同样,编写并发代码很困难,因此要保证存在没有并发性,这使得为解释器编写扩展更加容易。另外,这些扩展中的许多扩展只是现有库周围的薄包装,而编写这些库时可能并没有考虑到并发性。

评论


这与Java缺乏无符号数字类型的观点相同-开发人员认为其他所有人都比他们笨...

–基本
2015年10月6日在21:42

@Basic-信不信由你,即使你不是真的很傻,事实证明,拥有一种可以简化假设的语言仍然意味着有用,这些假设意味着您无需考虑某些事情就可以使它们起作用。事情。 CPython在某些方面非常有用,包括简单的多线程应用程序(其中的程序是受IO约束的,很多程序是受IO约束的,因此GIL无关紧要),因为使GIL成为最佳解决方案的设计决策也使对这些应用程序的编程更加容易,尤其是它支持对集合执行原子操作的事实。

–法律
18年7月21日在10:15

@Jules是的,在您需要这些功能之前,它非常方便。 cpython的“首选”解决方案“只需用另一种语言(如c ++)编写”就意味着您将失去所有的python好处。如果您使用C ++编写一半的代码,那么为什么要从Python开始?当然,对于小型API /胶水项目而言,它是快速简便的,而对于ETL,它是首屈一指的,但是它不适合需要大量工作的任何事物。就像使用Java与硬件进行通讯一样,这简直就是可笑的循环。

–基本
18年7月21日在12:23



@Basic Python的一种,因此扩展到CPython的核心理念是使该技术“友好且易于使用”。没有全局锁定的并行编程不是那样。考虑到有许多没有GIL的实现,因此至少提供一个包含GIL的实现是有意义的。

– Nearoo
19/12/15在17:11

您说“至少提供一个包含它的实现是有意义的”。就像这是显而易见的结论一样,但是我所知没有其他语言会以这种方式妨碍其开发人员,因此不会那么明显。

–基本
19/12/15在19:19

#3 楼

GIL的目的是什么?

CAPI文档对此有以下说法:


Python解释器不是完全线程安全的。为了支持多线程Python程序,有一个全局锁,称为全局解释器锁或GIL,必须由当前线程持有,然后才能安全地访问Python对象。如果没有锁,即使是最简单的操作也可能在多线程程序中引起问题:例如,当两个线程同时增加同一对象的引用计数时,引用计数最终只能被增加一次,而不是两次。 />

换句话说,GIL可以防止状态损坏。 Python程序绝不应该产生分段错误,因为仅允许内存安全操作。 GIL将这种保证扩展到了多线程程序。

有什么替代选择?

如果GIL的目的是保护状态免受损坏,那么一个明显的替代选择是锁定更细的颗粒;也许在每个对象级别。这样做的问题在于,尽管已证明它可以提高多线程程序的性能,但它具有更多的开销,因此单线程程序会受到影响。

评论


让用户运行一个具有解释器选项的程序来替换gil,以获得细粒度的锁定,并以某种只读方式知道当前进程是使用gil还是不使用gil引发的,这将是很好的。

–路易斯·马苏埃利(Luis Masuelli)
2014年12月17日在22:17

尽管有GIL,但由于粗心地使用了pyodbc模块,我还是在多线程程序中产生了分段错误。因此,“绝不应该产生分割错误”是谬论。

– Muposat
16年1月8日在7:35