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

科技 · 實用指南

Python 顯示「bootstrapping phase」?先證明 spawn 重新匯入了什麼

這個 RuntimeError 表示 child interpreter 重新匯入 entry module 時,import path 又啟動了 process。先記錄 start method 與 launcher,再移動完整呼叫鏈。

Python 顯示「bootstrapping phase」?先證明 spawn 重新匯入了什麼
原創技術示意圖: parent and child import boundary. Watch at Ease

這個 RuntimeError 表示 child interpreter 重新匯入 entry module 時,import path 又啟動了 process。先記錄 start method 與 launcher,再移動完整呼叫鏈。

只有原 launcher 重新執行後僅建立一個 parent、預期 workers 各執行一次並乾淨結束,而且不依賴強制變更 process method,修復才算完成。

1. 固定失敗 launch path

保存第一個 RuntimeError 的完整 traceback,記錄 Python、OS、sys.executable、sys.argv、__name__、__file__、get_start_method() 與實際 launcher。

_check_not_importing_main 前最上層 application frame 會指出 child 匯入 entry module 時哪個 import 或呼叫又建立 process。

2. 分離 import 與 entry-point 工作

definition、constant 與 import-safe setup 可留在 module scope。把 Pool、Process、Manager、ProcessPoolExecutor 和會建 worker 的 library call 移入 main(),只在 __main__ guard 下呼叫。

若 entry module 在 import 時已呼叫 helper,將 guard 放在 helper 內太晚;worker target 則應保留可匯入、可 pickle。

3. 實測 start method

Windows 使用 spawn,現代 macOS 預設 spawn;Python 3.14 起 POSIX 預設在支援處改為 forkserver。環境升級可能揭露 fork 曾掩蓋的遞迴 import。

不要強制 fork 來隱藏錯誤。需要明確方法時用 get_context,並在 application boundary 記錄,不要在 imported module 深處更改 global method。

4. 分支處理 frozen app 與第三方 pool

一般 interpreter 可省略 freeze_support;PyInstaller 因 child 重啟同一 executable 而覆寫它。通常在 guarded entry 呼叫,只有 import 更早啟動 multiprocessing 或 GUI 時才前移。

若 traceback 進入 library,確認 n_jobs、workers 或 processes 是否建 pool。單 worker 只適合診斷,恢復 parallelism 後 entry 仍須安全匯入。

5. 同 launcher 驗收

終止舊 process tree,再用相同 launcher 與 environment 全新啟動。確認 guard 僅在 parent、worker target 僅在 children 執行,且結束無 orphan。

將 traceback、launcher、start method、offending call chain、code movement 與 fresh result 保存成同一 audit record;source 與 packaged form 都要測。

Python 顯示「bootstrapping phase」?先證明 spawn 重新匯入了什麼
原創技術示意圖: guarded entry, packaging branch and fresh-run acceptance. Watch at Ease