Python 自由執行緒實驗性支援¶
從 3.13 版本開始,CPython 對一種稱為自由執行緒的 Python 構建版本提供了實驗性支援,該版本停用了全域性直譯器鎖 (GIL)。自由執行緒執行允許透過在可用 CPU 核心上並行執行執行緒來充分利用可用的處理能力。雖然並非所有軟體都能自動從中受益,但考慮到執行緒設計的程式將在多核硬體上執行得更快。
自由執行緒模式是實驗性的,並且正在進行改進工作:請預期一些錯誤以及單執行緒效能的顯著下降。
本文件描述了自由執行緒對 Python 程式碼的影響。有關如何編寫支援自由執行緒構建的 C 擴充套件的資訊,請參閱自由執行緒的 C API 擴充套件支援。
另請參閱
PEP 703 – 使 CPython 中的全域性直譯器鎖成為可選,其中對自由執行緒 Python 進行了總體描述。
安裝¶
從 Python 3.13 開始,官方 macOS 和 Windows 安裝程式可選地支援安裝自由執行緒 Python 二進位制檔案。安裝程式可在https://python.club.tw/downloads/上找到。
有關其他平臺的資訊,請參閱安裝自由執行緒 Python,這是一個由社群維護的安裝自由執行緒 Python 的指南。
從原始碼構建 CPython 時,應使用--disable-gil
配置選項來構建自由執行緒 Python 直譯器。
識別自由執行緒 Python¶
要檢查當前直譯器是否支援自由執行緒,python -VV
和sys.version
包含“experimental free-threading build”。新的sys._is_gil_enabled()
函式可用於檢查正在執行的程序中是否實際停用了 GIL。
sysconfig.get_config_var("Py_GIL_DISABLED")
配置變數可用於確定構建是否支援自由執行緒。如果變數設定為1
,則構建支援自由執行緒。這是與構建配置相關的決策的推薦機制。
自由執行緒 Python 中的全域性直譯器鎖¶
CPython 的自由執行緒構建支援在執行時使用環境變數PYTHON_GIL
或命令列選項-X gil
選擇啟用 GIL。
當匯入未顯式標記為支援自由執行緒的 C-API 擴充套件模組時,GIL 也可能會自動啟用。在這種情況下,將列印警告。
除了各個軟體包的文件之外,以下網站還跟蹤受歡迎的軟體包對自由執行緒的支援狀態
執行緒安全¶
CPython 的自由執行緒構建旨在在 Python 級別提供與預設啟用 GIL 的構建類似的執行緒安全行為。諸如dict
、list
和set
之類的內建型別使用內部鎖來防止併發修改,其行為方式與 GIL 類似。但是,Python 歷來沒有保證對這些內建型別的併發修改的特定行為,因此這應被視為當前實現的描述,而不是對當前或未來行為的保證。
注意
建議儘可能使用threading.Lock
或其他同步原語,而不是依賴內建型別的內部鎖。
已知限制¶
本節描述了自由執行緒 CPython 構建的已知限制。
永生化¶
3.13 版本的自由執行緒構建使一些物件永生化。永生物件不會被解除分配,並且其引用計數永遠不會被修改。這樣做是為了避免引用計數爭用,而這會阻止高效的多執行緒擴充套件。
在主執行緒執行後第一次啟動新執行緒時,物件將被永生化。以下物件將被永生化
由於永生物件永遠不會被解除分配,因此建立這些型別物件的許多應用程式可能會看到記憶體使用量增加。預計將在 3.14 版本中解決此問題。
此外,程式碼中的數字和字串字面量以及sys.intern()
返回的字串也被永生化。預計此行為將保留在 3.14 的自由執行緒構建中。
幀物件¶
從其他執行緒訪問幀物件是不安全的,這樣做可能會導致程式崩潰。這意味著sys._current_frames()
在自由執行緒構建中通常不安全。諸如inspect.currentframe()
和sys._getframe()
之類的函式通常是安全的,前提是不將生成的幀物件傳遞給另一個執行緒。
迭代器¶
在多個執行緒之間共享同一個迭代器物件通常是不安全的,並且執行緒在迭代時可能會看到重複或丟失的元素,或者使直譯器崩潰。
單執行緒效能¶
與預設的啟用 GIL 的構建相比,自由執行緒構建在執行 Python 程式碼時具有額外的開銷。在 3.13 中,pyperformance套件上的開銷約為 40%。在 C 擴充套件或 I/O 中花費大部分時間的程式將看到較小的影響。最大的影響是因為在自由執行緒構建中停用了專門的自適應直譯器(PEP 659)。我們希望在 3.14 版本中以執行緒安全的方式重新啟用它。預計在即將釋出的 Python 版本中,這種開銷將會減少。我們的目標是,與預設的啟用 GIL 的構建相比,pyperformance 套件上的開銷為 10% 或更少。