科技 · 实用指南
Python 报“bootstrapping phase”?移动 guard 前先证明 spawn 重导入了什么
该 RuntimeError 表示新子解释器重导入入口模块时,导入路径又启动了进程。先记录启动方法和启动器,再把所有创建进程的调用链移到真实入口边界之后。

该 RuntimeError 表示新子解释器重导入入口模块时,导入路径又启动了进程。先记录启动方法和启动器,再把所有创建进程的调用链移到真实入口边界之后。
只有原启动器重新运行后仅创建一个父进程、目标 worker 各执行一次并干净退出,而且不依赖强制切换进程方法,修复才算完成。
1. 固定失败的启动路径
保存第一次 RuntimeError 的完整 traceback,而不是后续重复副本。记录 Python 版本、操作系统、sys.executable、sys.argv、__name__、__file__、get_start_method(),以及终端、IDE、notebook、服务或冻结程序等启动器。
multiprocessing.spawn._check_not_importing_main 之前最靠上的应用栈帧最有价值,它指出子解释器导入入口模块时哪条调用链又创建了进程。
2. 把导入工作与入口工作分开
定义、常量和可安全导入的初始化可保留在模块级。把 Pool、Process、Manager、ProcessPoolExecutor、客户端构造和可能建 worker 的库调用移入 main(),只在 if __name__ == "__main__" 下调用。
若入口模块在导入时就调用 helper,把 guard 放进 helper 已经太晚。边界必须在子解释器进入所有建进程路径前停止它;worker 目标则保留在模块级,确保可导入和 pickle。
3. 实测启动方法,不要凭平台猜测
Windows 使用 spawn;现代 macOS 默认 spawn;Python 3.14 起,支持的平台上 POSIX 默认也从 fork 改为 forkserver。过去在 fork 下“能跑”的脚本,升级后可能暴露递归导入。
不要为了掩盖错误强制 fork。它并非处处可用,在多线程进程里也可能不安全。库需要指定方法时使用 get_context,并在应用边界记录,而不是在被导入模块里改全局状态。
4. 分开处理冻结程序与第三方池
普通解释器运行时,标准库示例说明可省略 freeze_support。PyInstaller 会覆盖该函数,因为冻结子进程会重启同一可执行文件;通常在受保护入口调用,只有导入会提前使用 multiprocessing、解析参数或启动 GUI 时才前移。
若 traceback 进入第三方库,确认 n_jobs、workers、processes 等选项是否创建池。单 worker 只是诊断控制,恢复并行后入口仍须可安全导入。
5. 用同一启动器验收
终止旧递归进程树,通过相同启动器和环境新启动。确认 guard 只在父进程执行、worker 目标只在子进程执行、输出不重复、退出后没有孤儿进程。
把 traceback、启动器、启动方法、触发调用链、代码移动与新运行结果放在同一记录。若同时发布源码与打包版本,两种形式都要测试。
