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