Python multiprocessing运行时main()前代码重复执行问题
现象产生原因
macOS 下 Python 3.8+ 版本的multiprocessing模块默认使用spawn方式启动子进程,Windows 系统也始终使用该启动模式。spawn模式不会像Linux默认的fork模式那样直接复制父进程的内存状态,而是会启动一个全新的Python解释器进程,重新导入主程序模块完成初始化。
你当前代码中,列表生成、print("hello\n")这类逻辑全部写在了主模块的顶层,没有放在if __name__ == "__main__":判断块内。子进程导入主模块时,这些顶层代码会被逐行执行:主进程启动时执行1次,你开了4个工作进程就会额外执行4次,总共打印5次hello,和你终端的输出完全吻合。
这种模式下如果顶层有文件写入、数据库连接、随机数生成这类逻辑,还会出现资源重复占用、子进程数据和主进程不一致等隐蔽bug。
跨平台多进程开发最佳实践
- 所有仅需主进程执行的逻辑:包括全局变量初始化、配置加载、测试打印、进程池创建、任务调度代码,必须全部放在
if __name__ == "__main__":判断块内部,或者放在被该块调用的入口函数中,绝对不要裸露在模块顶层。 - 不要依赖全局变量给子进程传参:
spawn模式下子进程的全局变量是重新导入模块生成的独立副本,和主进程的变量不共享,所有任务需要的参数必须通过Pool的map/starmap等方法显式传递。如果需要多进程共享状态,使用multiprocessing提供的Queue、Value、Array、Manager等专门的跨进程通信结构。 - 显式指定进程启动方式:在入口代码最开头、创建任何进程/进程池之前,调用
multiprocessing.set_start_method("spawn")统一全平台的进程启动行为,避免不同操作系统默认启动方式差异导致的诡异问题。注意该方法在整个程序生命周期中只能调用一次。
修正后的main.py参考代码
from multiprocessing import Pool, set_start_method from simulator.simulation import a_simulation import random def main(): num_trials = 10 iter_trials = list(range(num_trials)) arg_list = [random.random() for _ in range(num_trials)] input_args = list(zip(iter_trials, arg_list)) print("hello\n") with Pool(processes=4) as pool: result = pool.starmap(a_simulation, input_args) print(result) if __name__ == "__main__": set_start_method("spawn") main()
运行修正后的代码,hello只会在主进程启动时打印1次,不会再出现重复执行顶层逻辑的问题。
内容的提问来源于stack exchange,提问作者G. Z.
相关产品推荐
相关产品推荐

