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

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

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

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

7个解决方案

181 votes

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

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

更新:更新了指向Youtube的视频链接,因为之前的blip.tv链接已经丢失。

Vinay Sajip answered 2019-03-13T16:35:24Z

50 votes

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

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

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

Jon Skeet answered 2019-03-13T16:36:13Z

26 votes

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

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

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

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

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

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

Akshar Raaj answered 2019-03-13T16:37:47Z

14 votes

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

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

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

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

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

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

fulmicoton answered 2019-03-13T16:39:11Z

14 votes

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函数来完成昂贵的多线程事务。

Ijaz Ahmad Khan answered 2019-03-13T16:40:10Z

0 votes

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

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

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

如何从Python中删除它?

像Lua一样,也许Python可以启动多个VM,但python不会这样做,我想应该有其他一些原因。

在Numpy或其他一些python扩展库中,有时,将GIL发布到其他线程可以提高整个程序的效率。

maoyang answered 2019-03-13T16:41:20Z

0 votes

我想分享一本关于Visual Effects的多线程书的例子。 所以这是一个典型的死锁情况

static void MyCallback(const Context &context){

Auto 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 ║

╚═══╩════════════════════════════════════════╩══════════════════════════════════════╝

user1767754 answered 2019-03-13T16:41:57Z

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值