什么是一个全球性的解释锁和为什么一个问题吗?

一个很大的噪声已经围绕消除GIL从蟒蛇,我想要明白这是为什么如此重要。我从来没有写过一个编译器,也没有解释自己,所以不是节约的详细信息,我可能会需要他们理解的。

有帮助吗?

解决方案

Python的GIL旨在连续访问来自不同线程的解释器的内部。在多核心系统,这意味着多个线程不能有效地利用多个核心。 (如果GIL并没有导致这个问题,大多数人不会在乎GIL - 它只是被提出作为一个问题,因为多核系统的日益流行的。)如果你想了解它的细节,您可以查看这个视频或看的此组幻灯片的。这可能是信息太多,但你没有问细节: - )

请注意Python的GIL是唯一真正的CPython的,参考实现的问题。 Jython和IronPython的没有GIL。作为一个Python开发者,你一般不会遇到的GIL,除非你正在编写一个C扩展。 C扩展作家需要释放GIL时,他们的扩展做阻塞I / O,这样在Python进程的其他线程有机会运行。

其他提示

假设你有多个线程哪些没有的真正的触摸对方的数据。这些应该尽可能地独立执行。如果你有一个“全球锁”,你需要为了获取到(比如说)调用一个函数,能够最终成为一个瓶颈。您可以拉闸不摆在首位具有多线程得到多少好处。

要放到一个现实世界的类比:假如100个开发者在一个公司只有一个咖啡杯的工作。大多数开发商会花时间等待,而不是咖啡编码。

这一切都不是Python特定的 - 我不知道什么样的Python需要GIL在首位的细节。然而,希望它给你的一般概念的一个更好的主意。

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

的任何操作/指令在解释器执行。 GIL确保解释器由单个线程在举行的的特定时刻即可。和多线程的Python程序工作在一个单一的解释。在任何特定的时间瞬间,这个解释器由一个线程持有。这意味着,只有其保持解释器线程的运行是在的任何时刻

现在为什么会这样一个问题:

您机可以具有多个核/处理器。和多个核心允许多个线程在任何特定的时间瞬间执行的同时即多个线程可以执行的 即可。 但由于该解释由单个线程持有,其他线程没有做任何事情,即使他们有机会获得核心。所以,你是不是因为在任何时刻只有一个核心,这是正在使用的线程当前持有的解释的核心越来越被多个核心提供的任何优势,正在被使用。所以,你的程序将采取只要执行就好像它是一个单线程程序。

然而,可能阻塞或长时间运行的操作,如I / O,图像处理,并且NumPy的数字运算,发生的GIL外部。从这里。因此,对于这样的操作,多线程操作仍然会高于尽管GIL的存在单线程操作快。所以,GIL并不总是一个瓶颈。

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

的Python不允许在字的真正意义上的多线程。它具有多线程包,但如果你想多线程来加速你的代码了,那么它通常是不使用它是一个好主意。 Python有一个称为全局解释器锁(GIL)结构。

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

在GIL确保只有你的“线程”的人可以在任何时间执行。一个线程获得GIL,做一点点工作,然后经过GIL到下一个线程。这种情况非常快,对人的眼睛像你的线程并行执行它看起来可能,但使用相同的CPU核心,他们真的只是轮流。所有这一切GIL传递的开销增加了执行。这意味着,如果你想使你的代码运行得更快,然后使用线程包往往不是一个好主意。

有原因使用Python的线程包。如果你想同时运行一些东西,而效率是不是一个问题,那么它是完全正常和方便。或者,如果你正在运行的是需要等待的东西(像一些IO)代码,那么它可以使一个很大的意义。但是,线程库不会让你使用额外的CPU核心。

多线程可以外包给操作系统(做多处理),调用你的Python代码(例如,Spark或Hadoop的)一些外部应用程序或一些代码Python代码调用(如说:你可以有Python代码调用C函数,它的昂贵的多线程的东西)。

每当两个线程都访问同一个可变你有问题。 在C ++中,例如,以避免该问题的方法是定义一些互斥锁,以防止2个线程,让我们说,在同一时间输入的对象的设定器。

多线程能够在Python,但两个线程不能在同一时间被执行 在粒度细于一个蟒指令。 正在运行的线程是得到一个全局锁叫做GIL。

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

请注意,有可能释放GIL,如果你在C写的一种方法的例子里面。

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

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

蟒蛇3.7文件

我也谨强调以下引用的 蟒蛇 threading 文档:

CPython执行情况的详细说明:在CPython,由于全球解释锁,只有一线可执行代码一次(即使某些绩效为导向的图书馆可能克服这种限制).如果你想让你的申请,以便更好地利用计算的资源多核心机,都建议您使用 multiprocessingconcurrent.futures.ProcessPoolExecutor.然而,穿丝仍然是一个适当的模型,如果你想要跑多I/O定任务同时进行。

这个链接到 词汇表的条目 global interpreter lock 它解释说,吉尔,意味着螺纹并行在蟒蛇是不合适的 CPU定任务:

该机构使用的CPython解释,以确保只有一个线程执行Python码的时间。这简化了CPython实现通过使对象模型(包括重要的内置的类型(例如字典)隐式安全反对并行的访问。锁定整个解释使得它更容易为的解释是多线程,以牺牲的太多的并行提供的多处理机。

然而,一些扩展的模块,无论是标准的或第三方的设计,以便释放吉尔当做计算密集型任务,例如压缩或散列。此外,吉尔总是时释放的做I/O.

过去的努力,以创建一个"自由的螺纹"口译员(一个锁共享数据更精细粒度)没有成功,因为性能遭受的共同单处理的情况。据认为,克服这一性能的问题将使实现更复杂因而更昂贵的维护。

这句话还意味着字典和由此变量的分配也是线的安全作为一个CPython执行情况的详细说明:

接下来, 文档 multiprocessing 解释它是如何克服在吉尔通过产卵进程的同时暴露出一个界面类似于 threading:

多处理一封支持创建进程使用类似的线的模块。多处理软件包提供本地和远程并发,有效地侧步的全球解释锁使用子过程,而不是线。由于这个原因,多处理模块允许的程序,充分利用多个处理在给定的机。它运行的两Unix and Windows.

文档 concurrent.futures.ProcessPoolExecutor 解释说,它使用 multiprocessing 作为后端:

该ProcessPoolExecutor类是一个遗嘱执行人类使用的一个游泳池的进程,以执行的电话异步的。ProcessPoolExecutor使用多处理模块,这使得它能够侧步的全球解释锁还意味着,只有picklable对象可以执行并返回。

这应该是与其他基类 ThreadPoolExecutor使用螺纹,而不是过程

ThreadPoolExecutor是一个遗嘱执行人类使用的一个游泳池的线执行的电话异步的。

从这我们得出的结论, ThreadPoolExecutor 是只适用于I/O定任务,同时 ProcessPoolExecutor 也可以处理CPU定的任务。

以下问题的询问为什么吉尔存在的第一个地方: 为什么全球性的解释锁?

过程中vs线实验

多处理vs螺纹蟒蛇 我已经做了一个实验性的分析过程中vs螺纹蟒蛇。

快速预览的结果:

enter image description here

<强>为什么的Python(CPython的和其他)使用GIL

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

在CPython的,全局解释锁或GIL,是防止多个原生线程同时执行Python字节码互斥。这把锁是必要的,主要是因为CPython中的内存管理是不是线程安全的。

如何从Python中删除它吗

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

在numpy的或一些其它蟒扩展库,有时,释放GIL给其他线程可能促进整个程序的效率。

我想从书多线程为视觉效果共享的例子。因此,这里是一个典型的死锁情况

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                      ║
╚═══╩════════════════════════════════════════╩══════════════════════════════════════╝
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top