2010-05-13 62 views
3

Python解釋器具有全局解釋器鎖定,我的理解是擴展必須在多線程環境中獲取它。但Boost.Python HOWTO page表示擴展函數必須釋放GIL並在退出時重新獲取它。解釋Python擴展多線程

我要抵制誘惑,在這裏猜測,所以我想知道什麼應該是GIL鎖定模式在下列情況:

  1. 擴展從蟒蛇叫(大概在Python線程中運行)。
  2. 擴展的後臺線程回調Py_*函數。

而最後一個問題是,爲什麼鏈接的文檔說,GIL應被釋放並重新獲取的?

回答

4

只要Python解釋字節碼,GIL就會被當前正在運行的線程持有。在設法獲取GIL之前,沒有其他Python線程可以運行。

翻譯時呼籲爲本地代碼,代碼有關於GIL兩種選擇:

  1. 它可能什麼也不做。
  2. 它可以釋放GIL,而它的工作原理,然後再返回到Python

如果本地代碼使得很多電話回Python的運行時,它應該選擇1日之前重新獲得它:你永遠不能叫Python的運行時間除非你持有GIL(除了少數例外情況,例如,如果你沒有GIL,則可以撥打電話獲取GIL)。

如果本機代碼做了很多不涉及Python的工作,那麼您可以使用選項2:只要釋放GIL,Python就能夠調度另一個Python線程,以便獲得一些並行性。如果你沒有發佈GIL,那麼當你的Boost代碼運行時,Python的其他線程無法執行:這就是文檔告訴你釋放並重新獲取GIL的原因。

如果你這樣做,那麼在你釋放GIL之前或重新獲取它之前,你必須小心地使你能夠訪問Py_*函數。這可能意味着您必須創建本地數據副本,因爲在GIL發佈時您無法安全地訪問Python數據類型,例如列表或字典元素。

如果您的Boost代碼需要在GIL發佈時回撥到Python,那麼您需要獲取GIL,撥打電話,釋放GIL。儘量避免從非由Python創建的線程進行這種調用,因爲他們需要額外的工作才能獲取GIL。

+0

謝謝,這清除了事情。 但是,最後一件事情需要澄清:當Python代碼調用本地擴展代碼時,它可以選擇釋放GIL。但是,調用本地代碼時,callstack包含對諸如「PyObject_CallFunction」,「PyObject_Call」等Python函數的調用。 爲什麼在這些功能的上下文中釋放GIL是安全的? – 2010-05-13 23:41:13

+0

這些函數在展開堆棧並「返回」之前不會「執行」任何操作。那時你應該重新獲得GIL,以便他們能夠工作。 – 2012-12-04 08:18:08