在 GitHub Action 中使用 Free-threaded Python

迎接無 GIL 的混沌時代

Python 3.13 最近進入 GA 了,然後這當中就有個十分重量級的功能被合併進去——選擇性關閉全域直譯器鎖(GIL)

過去由於 GIL 的關係而導致 Python 中的 threading 基本上是殘廢狀態,隨著 Python 的生態系擴大與依賴於 Python 的服務愈長愈多,進而長出了各種用利用行程(process)代替執行緒(thread)的手段;但這些手段終究是在逃避問題,PEP-703 隨之浮出水面,期待有朝壹日 GIL 能正式地從 CPython 中被關閉。

回到開頭所提及的,這次 CPython 3.13 版中就包含了「選擇性地關閉 GIL 」的功能,在原文文件中則使用了「自由執行緒(free-threaded)」的字樣表達讓它自己飛;在這次的發佈中,這項功能被官方聲明為實驗性的、可選擇的功能,即不保證這個功能的完善、並且預設不會開啟,不過對於套件的開發者來說倒是可以開始測一下在解開束縛之後軟體是否會出各種意外。

畢竟多執行緒是個大大大坑啊...

vsvqv4hfogr81.webp

Source: r/ProgrammerHumor

由於自由執行緒 / free-threaded 名字比較長,接下來的文章中將使用「無 GIL」的字樣來表達有啟用這項功能的 Python。

背景

本文撰寫於 2024 年 10 月中旬,此時 Python 3.13.0 甫發布。

使用無 GIL 的 Python

根據 3.13 Release note,free-threaded 的預編譯執行檔會跟著 Windows 及 macOS 的預編譯安裝檔一起發佈,而 Linux 端看來是把決定權交給各發行版自行處理。

如果是從原始碼開始編譯,設定時需要補上 --disable-gil 參數來開啟這項功能,而編譯出來的執行檔會使用名稱 python3.13t

最理想的條件就是直接使用 actions/setup-python 然後呼叫 python3.13t,但檢查後可知 3.13 release 裡面並沒有提供這個執行檔。

解決方案

感謝 Installing a free-threaded Python 一文提供了指路明燈,不然我差點以為要手動編譯

在 Ubuntu 環境的話,deadsnakes 有提供無 GIL 版本的 Python:

sudo add-apt-repository ppa:deadsnakes
sudo apt-get update
sudo apt-get install python3.13-nogil

跟 Poetry 整合

由於我的開發環境是使用 Poetry 因此這邊附上的是跟 Poetry 整合完成後的版本:

jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Setup free-threaded Python
run: |
sudo add-apt-repository ppa:deadsnakes
sudo apt-get update
sudo apt-get install python3.13-nogil
- name: Get Poetry
run: pipx install poetry
- name: Checkout code
uses: actions/checkout@v4
- name: Install dependencies
run: |
poetry env use $(which python3.13t) # !IMPORTANT
poetry install
- name: Run PyTest
continue-on-error: true
run: poetry run pytest

注意到當中 poetry env use 是必要的,當沒有特別指定執行檔時會發生 Poetry 優先抓到 ubuntu-latest 環境中的 Python 3.10。

另外上面的範本中打開了 continue-on-error ,這樣就算測試失敗了 CI 還是會標記為成功,可以讓這隻測試不要阻擋到開發流程,有需要的時候再點進去觀察狀態。

驗證

在 Release note 裡面有提及:

To check if the current interpreter supports free-threading, python -VV and sys.version contain “experimental free-threading build”.

故可以加上一個 step 來確認當下版本:

- name: Validate
run: poetry run python -VV

輸出:

Python 3.13.0 experimental free-threading build (main, Oct 8 2024, 08:51:27) [GCC 13.2.0]

佚事

然後我要測的套件還是炸了 🫠

光是相依函式庫就還有問題

目前有注意到的是 cffi 還不是 thread-safe、故不提供 wheel,被標記在 cffi#119 列為已知問題。而 cryptography 的相依有 cffi。不過就算這個解掉了我也不是很肯定會不會有下一個坑。