2012-09-12 36 views
12

裏面我有一些功能使用__import__導入一個Python線程

特別是交互式加載Python模塊最近,我在一些文章偶然發現關於「進口鎖」在Python,即鎖定進口(不只是GIL)。但是這篇文章很舊,所以也許這不是真的。

這讓我想知道在線程中導入的做法。

  1. import/__import__線程安全嗎?
  2. 他們可以創造死鎖嗎?
  3. 它們是否會導致線程化應用程序中的性能問題?

編輯2012年9月12日

感謝偉大的答覆Soravux。 所以導入是線程安全的,我不擔心死鎖,因爲在我的代碼中使用__import__的函數不會互相調用。

是否知道即使模塊已經被導入,鎖是否被獲取? 如果是這樣,我應該查看sys.modules以檢查在調用__import__之前模塊是否已經被導入。

當然,這應該不會在CPython中產生很大的差異,因爲無論如何都有GIL。然而,它可能會對其他實現(如Jython或無堆棧python)產生很多不同。

編輯2012年9月19日

關於Jython的,這裏是他們在doc說什麼:

http://www.jython.org/jythonbook/en/1.0/Concurrency.html#module-import-lock

Python做,然而,定義一個模塊導入鎖,這是實現 Jython的。只要輸入任何名稱的 ,就會獲取該鎖。無論導入是否通過導入 聲明,內置的等效__import__或相關代碼,都是如此。這是 重要的是要注意,即使相應的模塊已經導入 ,模塊導入鎖仍然會被獲取,如果只是簡單地 。

因此,在導入之前檢查sys.modules似乎是有意義的,以避免獲取鎖。你怎麼看?

+1

我想他們是線程安全的,因爲正如你所說,解釋器阻止進口。我有興趣瞭解它們是否會以典型的非線程循環導入以外的其他方式導致死鎖。 –

回答

8

正常導入是線程安全的,因爲它們在執行前獲取導入鎖定,並在導入完成後釋放導入鎖定。如果使用可用的鉤子添加自己的自定義導入,請確保將此鎖定方案添加到它。 imp模塊可以訪問Python中的鎖定工具(imp.lock_held()/acquire_lock()/release_lock())。

使用此導入鎖不會創建任何死鎖或依賴性錯誤,而不會產生already known的循環依賴性。

在Linux上創建一個線程爲clone的低級調用,然後使用Python進行線程化操作。分叉和克隆在各個內存段上應用不同的行爲。例如,與克隆更多段的數據(數據(通常是COW),堆棧,代碼,堆)相比,只有堆棧不被線程共享,實際上不會共享其內容。 Python中的導入機制使用放置在堆棧上的全局名稱空間而不是,因此使用共享段及其線程。由於導入作品的副作用(即內存變化)在相同的片段中起作用,因此它表現爲單線程程序。不過,請注意在多線程程序的導入中使用線程安全庫。它導致混亂使用調用在這樣的環境中不是線程安全的函數。

順便說一句,Python中的線程程序遭受GIL這將不會允許很多性能增益,除非您的程序是I/O綁定或依賴C或外部線程安全庫(因爲它們在執行之前釋放GIL) 。由於這個GIL,在兩個線程中運行相同的導入函數不會同時執行。請注意,這只是CPython的一個限制,Python的其他實現將具有不同的行爲。

要回答你的編輯:導入的模塊都是由Python緩存的。如果模塊已經加載到緩存中,它將不會再次運行,導入語句(或函數)將立即返回。您不必在sys.modules中實現緩存查找,Python會爲您執行此操作,並且除了GIL以外,不會執行任何操作imp鎖定sys.modules查找。要回答你的第二次編輯:我更喜歡維護一個比簡單的代碼,而不是試圖優化對我使用的庫(在本例中是標準庫)的調用。其基本原理是執行某些操作所需的時間通常比導入模塊所需的時間要重要得多。此外,在整個項目中維護這種代碼所需的時間要比執行所需的時間要長。這一切歸結爲:「程序員的時間比CPU時間更有價值」。

+0

感謝您的回覆。我現在想知道,即使先前導入了模塊,是否獲取了導入鎖定(請參閱我的原始問題中的編輯)。 –

+0

編輯答案以反映您編輯的問題。關於其他Python風格的好處。 – Soravux

+1

我偶然發現了文檔的這一部分:http://docs.python.org/library/threading.html#importing-in-threaded-code,它命名了一些更多的方面。 – Alfe