線程安全#
NumPy 支援在多線程環境中使用,透過標準函式庫中的 threading
模組。許多 NumPy 操作會釋放 GIL,因此與 Python 中的許多情況不同,可以透過利用 Python 中的多線程並行性來提高並行效能。
最容易獲得效能提升的情況是,當每個工作線程擁有自己的陣列或一組陣列物件,且線程之間沒有直接共享資料時。由於 NumPy 為許多底層操作釋放 GIL,因此大部分時間花費在底層程式碼中的線程將並行運行。
在線程之間共享 NumPy 陣列是可能的,但必須極其小心,以避免在變更多個線程之間共享的陣列時產生線程安全問題。如果兩個線程同時讀取和寫入同一個陣列,它們最多會產生不一致、競爭的結果,這些結果是不可重現的,更不用說是正確的。也可能透過例如在另一個線程正在從陣列讀取資料以計算 ufunc 操作時調整陣列大小,來使 Python 解釋器崩潰。
未來,我們可能會在 ndarray 中添加鎖定,以使使用 NumPy 陣列編寫多線程演算法更安全,但目前我們建議專注於線程之間共享的陣列的唯讀存取,或者如果您需要變更和多線程,則添加您自己的鎖定。
請注意,*不*釋放 GIL 的操作不會從使用 threading
模組中獲得效能提升,而是可能更適合使用 multiprocessing
。特別是,對 dtype=object
的陣列的操作不會釋放 GIL。
自由線程 Python#
版本 2.1 新增。
從 NumPy 2.1 和 CPython 3.13 開始,NumPy 也實驗性地支援禁用 GIL 的 python 運行時環境。請參閱 https://py-free-threading.github.io 以獲取有關安裝和使用自由線程 Python 的更多資訊,以及關於在依賴 NumPy 的函式庫中支援它的資訊。
因為自由線程 Python 沒有全域解釋器鎖來序列化對 Python 物件的存取,所以線程有更多機會變更共享狀態並產生線程安全問題。除了上面提到的關於 ndarray 物件鎖定的限制之外,這也意味著 dtype=object
的陣列不受 GIL 保護,從而為在自由線程 python 之外不可能發生的 python 物件創建資料競爭。