当前位置:  开发笔记 > 编程语言 > 正文

CPython中的全局解释器锁(GIL)是什么?

如何解决《CPython中的全局解释器锁(GIL)是什么?》经验,为你挑选了6个好方法。

什么是全球解释器锁,为什么它是一个问题?

围绕从Python中删除GIL已经产生了很多噪音,我想知道为什么这么重要.我自己从未编写过编译器或解释器,所以不要节俭细节,我可能需要他们理解.



1> Vinay Sajip..:

Python的GIL旨在从不同的线程序列化对解释器内部的访问.在多核系统上,这意味着多个线程无法有效地利用多个核心.(如果GIL没有导致这个问题,大多数人都不会关心GIL - 由于多核系统的普及,它只会被提出作为一个问题.)如果你想详细了解它,您可以观看此视频或查看此幻灯片组.这可能是太多的信息,但后来你确实要求详细信息:-)

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


很好的答案 - 基本上它意味着Python中的线程只能阻止I/O; 您的应用永远不会超过处理器使用率的1 CPU核心
"作为一名Python开发人员,你通常不会遇到GIL,除非你正在编写一个C扩展" - 你可能不知道你的多线程代码以蜗牛的速度运行的原因是GIL,但是你'肯定会感受到它的影响.令人惊讶的是,利用带有Python的32核服务器意味着我需要32个进程以及所有相关的开销.
@PaulBetts:事实并非如此.性能关键代码可能已经使用C扩展,可以并且确实发布GIL,例如`regex`,`lxml`,`numpy`模块.Cython允许在自定义代码中释放GIL,例如,[`b2a_bin(data)`](https://gist.github.com/zed/3526111)
@Paul Betts:您可以使用[multiprocessing](https://docs.python.org/2/library/multiprocessing.html)模块获得超过1个处理器使用率的CPU代码.创建多个进程比创建多个线程"更重",但如果你真的需要并行完成工作,那么在python中,它是一个选项.

2> Jon Skeet..:

假设你有多个线程并没有真正触及彼此的数据.那些应该尽可能独立地执行.如果你有一个"全局锁定",你需要获取它来(比如说)调用一个函数,这可能最终成为一个瓶颈.你最终可以获得多线程的好处.

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

这些都不是特定于Python的 - 我不知道Python首先需要GIL的细节.但是,希望它能让您更好地了解一般概念.



3> Akshar Raaj..:

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

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

现在为什么这是一个问题:

您的计算机可能有多个核心/处理器.多核允许多个线程同时执行,即多个线程可以在任何特定时刻执行..但由于解释器由单个线程持有,因此其他线程即使可以访问核心也没有做任何事情.因此,您没有获得多个内核提供的任何优势,因为在任何时刻,只使用单个内核,即当前持有解释器的线程使用的内核.因此,您的程序将花费很长时间来执行,就像它是一个单线程程序一样.

但是,在GIL之外发生可能阻塞或长时间运行的操作,例如I/O,图像处理和NumPy数字运算.取自这里.因此,对于此类操作,尽管存在GIL,多线程操作仍将比单线程操作更快.因此,GIL并不总是瓶颈.

编辑:GIL是CPython的实现细节.IronPython和Jython没有GIL,所以一个真正的多线程程序应该可以在它们中,我以为我从来没有使用过PyPy和Jython,也不确定.


**注意**:PyPy有**GIL**._Reference_:[http://doc.pypy.org/en/latest/faq.html#does-pypy-have-a-gil-why](http://doc.pypy.org/en/latest/faq. HTML#不-pypy具备的,一个吉尔 - 为什么).虽然Ironpython和Jython没有GIL.

4> Ijaz Ahmad K..:

Python不允许在最真实的意义上使用多线程.它有一个多线程包,但如果你想多线程来加速你的代码,那么使用它通常不是一个好主意.Python有一个名为Global Interpreter Lock(GIL)的结构.

https://www.youtube.com/watch?v=ph374fJqFPE

GIL确保每次只能执行一个"线程".一个线程获取GIL,做一点工作,然后将GIL传递到下一个线程.这种情况很快发生,因此对于人眼看来,您的线程似乎并行执行,但它们实际上只是轮流使用相同的CPU核心.所有这些GIL传递都增加了执行的开销.这意味着如果您想让代码运行得更快,那么使用线程包通常不是一个好主意.

有理由使用Python的线程包.如果你想同时运行一些东西,效率不是一个问题,那么它就完全没问题了.或者,如果您正在运行需要等待某些事情的代码(例如某些IO),那么它可能会很有意义.但是线程库不会让你使用额外的CPU内核.

多线程可以外包到操作系统(通过多处理),一些调用Python代码的外部应用程序(例如,Spark或Hadoop),或者Python代码调用的一些代码(例如:你可以拥有你的Python)代码调用一个C函数来完成昂贵的多线程事务.



5> fulmicoton..:

只要两个线程可以访问同一个变量,就会出现问题.例如,在C++中,避免问题的方法是定义一些互斥锁,以防止两个线程同时进入对象的setter.

python中可以进行多线程处理,但是两个线程不能同时以比一条python指令更精细的粒度执行.正在运行的线程正在获得一个名为GIL的全局锁.

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

请注意,如果您在C中编写的方法中,可以释放GIL.

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

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



6> Ciro Santill..:

Python 3.7文档

我还要强调Python threading文档中的以下引号:

CPython实现细节:在CPython中,由于使用了全局解释器锁,因此只有一个线程可以一次执行Python代码(即使某些面向性能的库可能克服了此限制)。如果希望您的应用程序更好地利用多核计算机的计算资源,建议使用multiprocessingconcurrent.futures.ProcessPoolExecutor。但是,如果您要同时运行多个I / O绑定任务,则线程化仍然是合适的模型。

这链接到词汇表条目,global interpreter lock该条目解释为GIL暗示Python中的线程并行性不适合CPU绑定的任务:

CPython解释器用来确保每次只有一个线程执行Python字节码的机制。通过使对象模型(包括关键的内置类型,如dict)隐式地安全地防止并发访问,从而简化了CPython的实现。锁定整个解释器可以使解释器更容易成为多线程的,但会牺牲多处理器机器提供的许多并行性。

但是,某些扩展模块(标准的或第三方的)被设计为在执行诸如压缩或散列之类的计算密集型任务时释放GIL。另外,在执行I / O时,始终释放GIL。

过去创建“自由线程”解释器(一种以更精细的粒度锁定共享数据的解释器)的努力并未成功,因为在常见的单处理器情况下性能会受到影响。相信克服该性能问题将使实现更加复杂,因此维护成本更高。

此引号还暗示,作为CPython实现的细节,字典以及变量分配也是线程安全的:

Python变量赋值是原子的吗?

Python字典中的线程安全

接下来,该软件包的文档multiprocessing介绍了如何通过生成过程同时暴露类似于以下内容的接口来克服GIL threading

multiprocessing是一个程序包,它使用类似于线程模块的API支持生成过程。多处理程序包提供本地和远程并发,通过使用子进程而不是线程来有效地避开全局解释器锁。因此,多处理模块允许程序员充分利用给定机器上的多个处理器。它可以在Unix和Windows上运行。

以及用于concurrent.futures.ProcessPoolExecutor解释该文档multiprocessing用作后端的文档:

ProcessPoolExecutor类是Executor子类,它使用进程池异步执行调用。ProcessPoolExecutor使用多处理模块,该模块可以使其避开全局解释器锁,但也意味着只能执行和返回可拾取对象。

应对比于其他基类ThreadPoolExecutor的是使用线程而不是进程

ThreadPoolExecutor是一个Executor子类,它使用线程池异步执行调用。

从中我们得出结论,ThreadPoolExecutor它仅适用于I / O绑定的任务,同时ProcessPoolExecutor还可以处理CPU绑定的任务。

下面的问题询问为什么GIL首先存在:为什么使用全局解释器锁定?

进程与线程实验

在Multiprocessing vs Threading Python中,我对Python中的进程与线程进行了实验分析。

快速预览结果:

推荐阅读
LEEstarmmmmm
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有