全局解释器锁(GIL)似乎经常被引用为Python中线程之类的操作比较棘手的主要原因-这就提出了一个问题:“为什么首先要这样做?”
不是程序员,我不知道为什么会这样-放入GIL的逻辑是什么?
全局解释器锁(GIL)似乎经常被引用为Python中线程之类的操作比较棘手的主要原因-这就提出了一个问题:“为什么首先要这样做?”
不是程序员,我不知道为什么会这样-放入GIL的逻辑是什么?
Answers:
有几种Python实现,例如CPython,IronPython,RPython等。
他们中有些人有GIL,有些人没有。例如,CPython具有GIL:
来自http://en.wikipedia.org/wiki/Global_Interpreter_Lock
可以将用GIL用编程语言编写的应用程序设计为使用单独的进程来实现完全并行性,因为每个进程都有自己的解释器,进而有自己的GIL。
GIL的好处
为什么Python(CPython等)使用GIL
在CPython中,全局解释器锁(即GIL)是一个互斥体,可以防止多个本机线程一次执行Python字节码。锁定是必要的,主要是因为CPython的内存管理不是线程安全的。
GIL之所以引起争议,是因为它在某些情况下阻止多线程CPython程序充分利用多处理器系统。请注意,潜在的阻塞或长时间运行的操作(例如I / O,图像处理和NumPy数字运算)发生在GIL之外。因此,只有在GIL内部花费大量时间解释CPython字节码的多线程程序中,GIL才成为瓶颈。
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不会妨碍您。
使用GIL发布时,可以类似地调用C或Fortran中的数字库。当您的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损害了您的性能(请参阅上面的讨论),则可以让您的线程产生一个进程并等待其完成。
s/RPython/PyPy/g
。@MichaelBorgwardt给出原因,专业GIL是问题的重点,不是吗?尽管我同意这个答案的某些内容(即关于替代方案的讨论)不重要。不管是好是坏,现在几乎都不可能消除引用-它在整个API和代码库中根深蒂固;如果不重写一半代码并破坏所有外部代码,几乎要摆脱它。
multiprocessing
库-自2.6起的标准库。对于某些简单类型的并行机制,它的工作池是一个非常漂亮的抽象。
首先,Python没有GIL。Python是一种编程语言。编程语言是一组抽象的数学规则和限制。Python语言规范中没有任何内容表明必须有一个GIL。
Python有许多不同的实现。有些有GIL,有些则没有。
拥有GIL的一种简单解释是编写并发代码很困难。通过在代码周围放置一个巨大的锁,您可以强制其始终串行运行。问题解决了!
特别是在CPython中,一个重要的目标是使使用C语言编写的插件扩展解释器变得容易。同样,编写并发代码很困难,因此通过保证不存在并发性,可以更轻松地为口译员。另外,这些扩展中的许多扩展只是现有库的精简包装,而编写这些库时可能并没有考虑到并发性。
GIL的目的是什么?
CAPI文档对此有此说法:
Python解释器不是完全线程安全的。为了支持多线程Python程序,有一个全局锁,称为全局解释器锁或GIL,必须由当前线程持有,然后才能安全地访问Python对象。如果没有锁,即使是最简单的操作也可能在多线程程序中引起问题:例如,当两个线程同时增加同一对象的引用计数时,引用计数最终只能被增加一次,而不是两次。
换句话说,GIL可以防止状态损坏。Python程序绝不应该产生分段错误,因为仅允许内存安全操作。GIL将这种保证扩展到了多线程程序。
有哪些选择?
如果GIL的目的是保护国家免遭腐败,那么一个明显的选择是锁定更精细的粮食。也许在每个对象级别。这样做的问题是,尽管已证明它可以提高多线程程序的性能,但它具有更多的开销,因此,单线程程序会受到影响。