TL;DR:想確認 python 有沒有真的關掉 GIL,跑
python -VV看是不是 free-threading build,import 完所有套件之後跑sys._is_gil_enabled()(3.13 起才有),輸出是False才代表這次執行真的沒有 GIL。3.14 起 free-threading 正式支援、但目前還不是預設項目;關掉 GIL 的影響是單執行緒變慢,以及沒支援的 C 擴充套件一被匯入就會把 GIL 重新開起來。
Python 3.14 起,free-threading build 從實驗性變成正式支援。這類的 build 可以在不啟用 GIL 的情況下跑 Python 程式,執行檔通常叫 python3.14t,跟一般的 python3.14 並存。GIL 拿掉之後,多執行緒才可能真的同時執行 Python;但拿掉 GIL,也會影響其他地方。
GIL
GIL 是 CPython 的全域直譯器鎖,作用是不讓多個執行緒同時執行 Python 程式(PEP 703 說明 prevents multiple threads from executing Python code at the same time)。它的核心理由跟記憶體管理相關。CPython 靠參考計數回收物件,每當有變數指到或不再指到某個物件,那個物件的計數就要加一或減一;而在有 GIL 的前提下,同一時間只有一個執行緒在跑。
要拿掉 GIL,這套邏輯作法就會不一樣。PEP 703 提的做法之一,是把原本非原子的參考計數換成 biased reference counting 這種執行緒安全的計數方式(a switch from plain non-atomic reference counting to biased reference counting)。實作細節這邊不討論,重點的差別是 GIL 換來的其實是「參考計數不必加鎖」;如果拿掉,就得在計數機制上把執行緒安全補回來。
3.14起正式支援
3.13 一開始加入 free-threading 時還是實驗性的。到 3.14 就變成正式性質,“The free-threaded build of Python is now supported and no longer experimental”。對應的規範是 PEP 779,它替「轉到正式支援」這個階段訂定出明確的條件(requirements for moving to Phase II, making the free-threaded Python build officially supported)。
但是正式支援不等於預設。整件事分成幾個階段:Phase II 讓 free-threaded build 變成官方支援、但仍然是選用的,要到 Phase III 才會讓它成為預設(officially supported but still optional, and phase III would make the free-threaded build the default)。以目前的資料看,裝好標準的 python3.14,預設仍然是 GIL 的版本,要 free-threading 得另外取得 free-threading build。
判斷狀態:build、執行期
這是最容易搞混的地方,因為要分兩個地方看。
第一,是安裝的 python 本身支不支援 free-threading。直接跑 python -VV,輸出的版本資訊裡如果寫著 free-threading build,就是支援的 build。程式內也可以查詢編譯設定:
import sysconfig
sysconfig.get_config_var("Py_GIL_DISABLED")
回 1 代表這個 build 支援 free threading(then the build supports free threading),回 0 或 None 就是一般的帶 GIL build。
第二,是這次執行到底有沒有真的把 GIL 關掉。3.13 起有個函式可以查詢:
import sys
sys._is_gil_enabled()
如果回 False 才代表這次跑起來 GIL 是關的(HOWTO:can be used to check whether the GIL is actually disabled in the running process)。那你可能會想支援的 build 為什麼還開著 GIL?有兩種情況。一種是明確要求:設環境變數 PYTHON_GIL=1,或啟動時加 -X gil=1,都會把 GIL 開回來(反過來 PYTHON_GIL=0 或 -X gil=0 是關)。另一種比較隱性、也比較常遇到:匯入沒有標記支援 free-threading 的 C 擴充套件時,直譯器會自動把 GIL 重新開起來。
隱性最值得被記住,因為它會讓兩個地方對不起來:build 明明支援,sys._is_gil_enabled() 卻回 True。所以要確認就要把查詢寫在 import 完所有套件之後跑,而不是一開機、還沒載入依賴就執行。
關掉之後
效能上,關掉 GIL 會讓單執行緒的程式變慢,因為參考計數改成執行緒安全的版本、以及其他為了無鎖並行做的調整。這裡有兩組官方數字,What’s New 3.14:單執行緒的效能損失目前大約落在 5 到 10%,會隨平台和 C 編譯器而變(roughly 5-10%)。HOWTO 則是 pyperformance 的實測範圍,平均開銷從 macOS aarch64 上約 1%,到 x86-64 Linux 上約 8%(the average overhead ranges from about 1% on macOS aarch64 to 8% on x86-64 Linux systems)。大家真的想知道可以實際量測差別,以及自己開發產品的類型來決策。

