Watch at Ease看見世界,讀懂生活。

科技 · 實用指南

Python 3.14行程池在沙箱中失敗?先測試forkserver的Unix通訊端

Python 3.14行程池可能在序列化工作前失敗。先區分暫存目錄不可寫與AF_UNIX策略拒絕,再選spawn、單一worker或有依據的上下文。

從主行程、暫存目錄與AF_UNIX通訊端到forkserver的診斷流程。
原創插畫:改變多行程語意前,先定位worker啟動前的故障。 Watch at Ease

Python 3.14把受支援POSIX系統的預設啟動方式從fork改成forkserver。這個較安全的預設會啟動獨立伺服器並使用本機Unix通訊端,因此受限工作可能在worker匯入模組或收到任務前失敗。

不要把所有追蹤都當成pickle錯誤,也不要自動用fork脫困。先確認故障在暫存空間、AF_UNIX建立或綁定、路徑長度、主模組匯入,或工作序列化;每個邊界需要不同修復。

1. 在第一個worker前定位故障

記錄sys.version、platform.platform()、get_start_method()與完整追蹤。若末端在forkserver.ensure_running、arbitrary_address、gettempdir或listener.bind,使用者函式還沒執行。

分開識別沒有可用暫存目錄、AF_UNIX路徑太長,以及建立或綁定的EPERM。後續PicklingError、本機函式AttributeError或主模組遞迴啟動才是匯入與序列化分支。

2. 分別測試暫存目錄與Unix通訊端

以與失敗工作相同的沙箱和使用者執行一次性探針。建立暫存目錄、綁定本機AF_UNIX路徑,然後關閉並刪除;它不建立網路服務。

mkdtemp失敗就修復暫存邊界或升級到有回退的補丁;目錄成功但AF_UNIX得到EPERM時,改TMPDIR不能授予能力;兩者都成功後再測單元素forkserver池。

3. 正確閱讀補丁版本界線

目前3.14手冊說明受支援POSIX預設forkserver;自3.14.9起,沒有可寫暫存目錄時預設spawn。更早版本可能直接OSError。

這個回退很窄。可寫目錄與AF_UNIX被沙箱拒絕可以同時存在;路徑太長又是不同問題。先保存異常、版本與路徑。

4. 選擇最窄且安全的回應

應用可用get_context('spawn')或ProcessPoolExecutor的mp_context。worker放模組頂層,入口加main保護,只傳可pickle資料。函式庫接受呼叫者上下文,不改全域方式。

工具支援worker數量時,單一worker通常是最小退路。必須平行時,請環境擁有者評估最小本機Unix通訊端許可,不以遠端服務繞過。

只有證明沒有不安全執行緒或函式庫狀態被複製時才用fork。能跑只證明能力,不證明安全。

5. 在spawn下重測語意

spawn啟動新直譯器。將巢狀函式與lambda移到可匯入模組作用域,保護入口,並在initializer重建每行程資源。不同上下文的鎖可能不相容。

不要傳開啟中的資料庫連線、事件迴圈或即時客戶端;傳設定與ID,在worker內開啟資源。

6. 以邊界矩陣驗收

記錄暫存目錄、AF_UNIX綁定、單元素forkserver池與spawn池,再以單一worker和選定上下文執行真實工具,保存退出碼與產物雜湊。

目標分支成功、無效目標仍以預期匯入或pickle錯誤失敗、退出後無通訊端殘留且輸出符合單worker基線,才算完成。

forkserver、spawn與fork的需求、故障訊號和第一步決策。
原創技術插畫:把啟動上下文視為應用契約,而非可任意交換的開關。 Watch at Ease