2009-08-18 125 views
145

什麼是全局解釋器鎖,爲什麼它是一個問題?什麼是全局解釋器鎖(GIL)?

大量的噪音,已經取得了從周圍的Python去除GIL,我想知道爲什麼是如此的重要。我從來沒有編寫過編譯器和解釋器,所以不要因爲細節而節儉,我可能需要他們去理解。

+0

可能重複的[Why the Global Interpreter Lock?](http://stackoverflow.com/questions/265687/why-the-global-interpreter-lock) – 2015-09-10 10:03:42

回答

144

Python的GIL旨在序列化來自不同線程的解釋器內部的訪問。在多核系統上,這意味着多線程無法有效利用多核。 (如果GIL沒有導致這個問題,大多數人不會關心GIL--由於多核系統的普及程度越來越高,它只是被提出來作爲一個問題。)如果你想詳細瞭解它,您可以查看this video或查看this set of slides。這可能是信息太多了,但你沒詢問詳情:-)

需要注意的是Python的GIL是唯一真正的CPython的,參考實現的問題。 Jython和IronPython沒有GIL。作爲Python開發人員,除非您正在編寫C擴展,否則通常不會遇到GIL。 C擴展編寫者需要在其擴展阻塞I/O時釋放GIL,以便Python進程中的其他線程有機會運行。

更新:更新後的視頻鏈接指向Youtube,因爲之前的blip.tv鏈接已經腐爛。

+31

好的答案 - 基本上,這意味着Python中的線程只適用於阻止I/O;你的應用程序永遠不會超過1個處理器使用的CPU核心 – 2009-08-18 15:26:29

+5

「作爲一名Python開發人員,除非你正在編寫C擴展程序,否則通常不會遇到GIL」 - 您可能不知道多線程的原因以蝸牛速度運行的代碼是GIL,但你一定會感受到它的影響。令我驚訝的是,利用Python的32核心服務器意味着我需要32個進程以及所有相關的開銷。 – Basic 2014-01-07 17:42:36

+5

@PaulBetts:這是不正確的。性能關鍵代碼很可能已經使用了可以釋放GIL的C擴展,例如'regex','lxml','numpy'模塊。 Cython允許在自定義代碼中釋放GIL,例如['b2a_bin(data)'](https://gist.github.com/zed/3526111) – jfs 2015-08-16 13:34:10

41

假設你有多個線程這不真的觸摸對方的數據。那些應該儘可能地獨立執行。如果你有一個「全局鎖定」,你需要獲取以便(稱)調用一個函數,這可能最終成爲一個瓶頸。首先,您可以從多線程中獲益不多。

爲了把它變成一個真正的世界類比:假如100個開發者在一個公司只有一個咖啡杯的工作。大多數開發者會花時間等待咖啡而不是編碼。

無的,這是Python特定的 - 我不知道什麼樣的Python需要GIL在首位的細節。不過,希望它給你一個更好的概念概念。

+0

但是,如果開發者在做票務支持,而不是(寫作2 - 分鐘回覆,然後等待1小時),儘管只有一個咖啡杯,但他們都會很有成效。 – 2017-06-28 10:28:09

1

維基百科有一個全球性的解釋的一個很好的說明鎖

http://en.wikipedia.org/wiki/Global_Interpreter_Lock

這個漂亮的文章,討論在Python的GIL那篇文章的鏈接。

http://www.ddj.com/linux-open-source/206103078?pgno=2

+0

可能最好鏈接到DDJ文章的開頭部分 - http://www.ddj.com/linux-open-source/206103078 – 2009-08-18 15:02:19

+5

謝謝,但我在做這個問題之前做了功課,當然還是去了谷歌和維基百科第一。 – 2009-08-18 15:02:47

13

當兩個線程可以訪問相同的變量,你有問題。 在C++中,避免此問題的方法是定義一些互斥鎖,以防止兩個線程同時進入對象的setter。

多線程是可能的在python中,但兩個線程不能在同一時間執行 在粒度比一個python指令更精細。 正在運行的線程正在獲取一個名爲GIL的全局鎖。

這意味着,如果你開始爲了充分利用你的多核處理器的寫一些多線程代碼,你的表現也不會提高。 通常的解決方法包括進行多進程。

請注意,如果您使用C編寫的方法,則可以釋放GIL。

GIL的使用不是Python固有的,而是它的一些解釋器,包括最常見的CPython。 (#edited,見註釋)

的GIL問題仍然是有效的Python 3000

+0

Stackless仍然有一個GIL。 Stackless不會改進線程(如在模塊中) - 它提供了一種不同的編程方法(協程),它嘗試側重解決問題,但需要非阻塞函數。 – jnoller 2009-08-18 16:24:02

+0

好點。感謝您的評論 – fulmicoton 2009-08-18 22:19:26

+0

3.2中的新GIL如何? – new123456 2011-07-07 01:11:56

7

Watch David Beazley告訴你所有你想知道的一切GIL。

+3

他是一位出色的談話者 - 如果有人會說服你,GIL很糟糕,那就是他。 – new123456 2011-07-07 01:11:32

+1

鏈接已死亡。 :( – szeitlin 2015-05-11 17:09:53

+3

David Beazley - 瞭解Python GIL - https://www.youtube.com/watch?v=Obt-vMVdM8s – 2015-06-14 21:16:48

13

讓我們先了解一下Python的GIL提供:

的任何操作/指令的解釋執行。 GIL確保解釋者在的特定時刻由單個線程持有。而你的多線程python程序在一個解釋器中工作。在任何特定的時刻,這個解釋器都由一個單獨的線程保存。這意味着只有拿着解釋器的線程是運行任何時刻

現在爲什麼是一個問題:

您的機器可能在具有多個核心/處理器。多核允許多個線程同時執行即多個線程可以在任何特定時刻執行。 但是由於解釋器是由單個線程保存的,其他線程即使可以訪問內核也不會做任何事情。因此,您沒有獲得多核心提供的任何優勢,因爲在任何時候,只有一個核心(目前正在使用該解釋程序的線程使用的核心)正在被使用。所以,你的程序需要很長時間來執行,就好像它是一個單線程程序一樣。

但是,潛在的阻塞或長時間運行的操作(例如I/O,圖像處理和NumPy數字運算)發生在GIL之外。取自here。因此,對於這樣的操作,儘管存在GIL,但多線程操作仍然比單線程操作更快。所以,GIL並不總是一個瓶頸。

編輯:GIL是CPython的實現細節。 PyPy和Jython沒有GIL,所以一個真正的多線程程序應該是可能的,我認爲我從來沒有使用PyPy和Jython,並且不確定這一點。

+3

** Note **: PyPy有** GIL **。_參考:[http://doc.pypy.org/en/latest/faq.html#does-pypy-have-a-gil-why](http://doc.pypy .org/en/latest/faq.html#does-pypy-have-a-gil-why)。雖然Ironpython和Jython沒有GIL。 – 2016-06-08 06:27:36

+0

確實,PyPy有一個GIL,但IronPython沒有。 – Emmanuel 2018-01-17 14:47:48

0

爲什麼的Python(CPython的和其他人)使用GIL

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

在CPython中,全局解釋鎖,或GIL是一個互斥體,可以防止多個本地線程一次執行Python字節碼。這個鎖主要是因爲CPython的內存管理不是線程安全的。

如何從Python中刪除它?

就像Lua一樣,也許Python可以啓動多個虛擬機,但是python沒有這樣做,我想應該有其他一些原因。

在Numpy或其他一些Python擴展庫中,有時將GIL釋放到其他線程可能會提高整個程序的效率。

1

我想分享本書多線程Visual Effects的示例。因此,這裏是一個典型的死鎖情況

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      ║ 
╚═══╩════════════════════════════════════════╩══════════════════════════════════════╝ 
4

的Python不允許在這個詞的真正意義上的多線程。它有一個多線程包,但如果你想用多線程來加速你的代碼,那麼使用它通常不是一個好主意。 Python有一個叫做Global Interpreter Lock(GIL)的構造。 GIL確保只有一個'線程'可以在任何時候執行。線程獲取GIL,做一些工作,然後將GIL傳遞到下一個線程。這種情況發生得非常快,所以對於人眼而言,它可能看起來像你的線程並行執行,但它們實際上只是輪流使用相同的CPU內核。所有這些GIL通過都會增加執行的開銷。這意味着如果你想讓你的代碼運行得更快,那麼使用線程包通常不是一個好主意。

有理由使用Python的線程包。如果你想同時運行一些東西,而且效率不是問題,那麼它就非常好,很方便。或者如果你正在運行需要等待某些事情的代碼(比如一些IO),那麼它可能會很有意義。但線程庫不會讓你使用額外的CPU核心。多線程可以外包給操作系統(通過執行多處理),某些調用Python代碼的外部應用程序(例如Spark或Hadoop)或一些代碼(Python代碼)(例如:你可以讓你的Python代碼調用一個執行昂貴的多線程的C函數)。