別把 GIL 時代的思維帶進 Free-threaded Python:從 Rust 視角重新理解 Python 並行

Xavier Yen (顏志穎)

Xavier Yen (顏志穎)

Day 1 • Sat, Oct 17
14:00 - 14:45
Location
R0
Language
Chinese (English slides)
Category • Level
Python Core • Expert

為了避免重複的耗時運算,你是否也曾利用字典把計算結果存起來,以便下次直接取用?如果只寫單執行緒腳本,這樣的程式碼完美無瑕,但在多執行緒環境下,它其實已經踩在懸崖邊緣,只是 GIL 一直在背後幫我們擋著。

從 Python 3.13 引入實驗性的 free-threaded build 到 3.14 升級為官方正式支援,「沒有 GIL 的 Python」已不再是未來式,當這層保護傘被拿掉,我們才會發現自己過去寫的 Python 默默預設了非常多「GIL 存在」才能成立的假設。

過去兩年實作原生擴充的經驗讓我深刻體悟到,用 Rust 的思維思考並行時,free-threaded Python 的全貌便豁然開朗,Rust 編譯器強制要求我們想清楚的細節,完美對應了它交還給開發者的安全責任。

本場演講將從 Rustacean 的視角出發,透過已實測的並行任務範例 (同一份純 Python 多執行緒程式碼,只差一個 GIL 開關,加速從 1.05 倍變 5.1 倍),搭配 PyO3 的設計選擇,帶大家回頭檢視我們對 Python 並行的種種預設。

即使完全沒寫過 Rust,離開會場時也能以全新的眼光,重新審視自己日常撰寫的 Python 程式碼。 本演講假設聽眾具備 Python 開發經驗,並對多執行緒 (threading) 有基本認識,不需要 Rust、PyO3 經驗。

Description

從 PEP 703 (2023) 將 GIL 設定為可選、PEP 779 (2025) 把 free-threaded build 從實驗升級為 officially supported,到 PEP 803 (已 Accepted,目標 3.15) 為其定義 stable ABI,CPython 正在進行三十年來最大的並行模型轉變。 縱使這樣的改變令人感到興奮,但也帶來了不可避免的代價:長期由 GIL 隱性處理的執行緒安全責任,正被重新交還給開發者。 許多在 GIL 時代「能跑」的 Python 程式碼,在 free-threaded build 下會出現 race condition、資料損毀、或邏輯錯誤,具體例子包含 lazy initialization 模式、模組層級 cache、共享計數器 (counter += 1),以及對「文件標明 not thread-safe 但實務上沒事」函式庫的依賴。

為什麼從 Rust 視角切入

面對多執行緒的挑戰,Rust 長期引以為傲的核心哲學正是「無畏並行」(Fearless Concurrency)。 以 Python 生態系中最主流的原生擴充框架 PyO3 為例,就能看出這項優勢如何大顯身手。 它從 Python 引入實驗性 free-threaded build 起便同步加入支援,並把 Rust 編譯期嚴格檢驗的 Send / Sync traits,直接對應到 Python 物件的執行緒安全契約上,穩穩接住了 free-threaded 拋回給開發者的安全責任。

這種從「依賴 GIL」轉向「擁抱型別安全」的典範轉移,也一路推動著 PyO3 的 API 演進:從 0.26 把 Python::with_gil 改名為 Python::attachPython::allow_threads 改名為 Python::detach,將「鎖 GIL」的語意翻轉為「執行緒對直譯器的接入與退出」;0.28 進一步把模組預設值改為 free-thread-safe;到了 0.29 則實作 PEP 803 的 abi3t stable ABI,同時收掉實驗性的 3.13t 支援、專注於穩定的 3.14t+。

PyO3 正在系統性地將 GIL 時代的歷史包袱從 API 中清除,從用語、預設值到 ABI 的層層翻新透露出:free-threaded Python 真正改變的不只是直譯器,還有它要求每一位開發者具備的並行心智模型,而這條演化軌跡,正是這場轉換最早的可見證據。 好消息是,這套新的心智模型不必從零摸索,它剛好就是 Rust 型別系統一直以來強制我們想清楚的那一套。與其在多執行緒的深水區裡摸黑試錯,不如直接借用 Rust 的思維,為這場並行革命打下穩固的基礎。

演講中將呈現的具體範例

我設計了一個簡單的「紅包驗證任務」:對一批資料執行 CPU-bound 的驗證與統計,並實作了四個版本:純 Python (單/多執行緒)、PyO3 native 平行版 (轉為 Rust struct,detach 直譯器後用 rayon 運算),以及 PyO3 interpreter-bound 平行版 (在平行區內 attach 狀態下呼叫 Python callback)。 此任務在 Python 3.14 free-threaded 環境下,透過 -X gil 開關做了 8 執行緒的對照實測,得到三個發現:

  1. 純 Python 多執行緒:關閉 GIL 後,加速比從 1.05x 躍升至 5.10x,而且完全不用碰 Rust。
  2. PyO3 native 平行版:無論 GIL 開關,速度幾乎沒有差別 (約 1.0x)。
  3. PyO3 interpreter-bound 平行版:關閉 GIL 後獲得約 6.0x 的顯著加速。

這三個數字擺在一起,自然浮出兩個問題:為什麼 native 版拿掉 GIL 反而無感?interpreter-bound 版的紅利又是從哪裡來的?這條分界線正是 free-threading 真正解鎖了什麼的答案,也是演講要拆解的核心。 而範例中的共享計數器,正是開頭那個 counter += 1 災難的翻版。面對這種共享可變的累加器,Rust 在編譯期就直接拒絕,我會帶大家從編譯錯誤一路修到 AtomicU64,看 Rust 思維如何照亮 free-threaded Python 的盲點。

為什麼這場演講對不寫 PyO3 的人同樣重要

以最常見的 pandas 與 SQLAlchemy 來說,它們都已出現在社群的 free-threading 相容性追蹤清單中,但其官方文件裡的 thread-safety 警告依然有效。「套件支援 free-threading」屬於套件層相容性,由套件作者負責;「你的用法 thread-safe」屬於應用層責任,套件作者沒辦法替你決定怎麼用,本演講闡述的心智模型是應用層責任的思考工具,其中每個概念都將搭配一段純 Python(threading)對照程式碼,聽眾完全不碰 Rust 或 PyO3 也能立即用進自己的專案。

本演講不涵蓋的範圍

  • Rust 語法教學(不需要 Rust 經驗即可理解全部內容)
  • PyO3 專案的建置與部署細節
  • CPython 內部實作(free-threaded GC、reference counting 機制等)
  • Polars、Pydantic 等基於 PyO3 的工具的使用指南

參考資料

Xavier Yen (顏志穎)
Xavier Yen (顏志穎)

《從 Pythonista 到 Rustacean:資料從業者的第一本 Rust 指南》(深智數位,2026)作者,PyO3、HuggingFace Candle 等開源專案貢獻者,Rust AI coding agent「zerostack」共同維護者。現為外商電信設備商資料工程師,個人網站 xavierforge.dev 🦀🦀🦀 Author of "From Pythonista to Rustacean" (in Traditional Chinese; 深智數位, 2026), contributor to open-source projects including PyO3 and HuggingFace Candle, and co-maintainer of zerostack, a Rust AI coding agent. Data engineer at a multinational telecom equipment vendor. Personal website: xavierforge.dev

Related Speeches