防止池进程导入__main__和全局变量

3 投票
1 回答
572 浏览
提问于 2025-04-16 17:24

我正在使用一个多进程的工作池,这个池子是我一个更大应用的一部分。因为我用它来处理大量简单的数学运算,所以我采用了“无共享”架构,也就是说,工作者只需要通过参数传递的变量。这样,我就不需要让工作进程去导入任何全局变量、我的 __main__ 模块,或者它所导入的任何模块。因此,我想知道有没有办法强制实现这种行为,从而避免在创建工作池时性能下降。

我需要说明的是,我的环境是Win32,这里没有 os.fork() 这个功能,工作进程是通过“调用 sys.executable(也就是启动一个新的Python进程),然后序列化所有全局变量,并通过管道发送这些变量”来生成的,具体可以参考这篇帖子。所以,我希望尽量减少上述操作,以便我的工作池能更快地启动。

有没有什么好主意呢?

1 个回答

4

在查看multiprocessing.forking的实现时,特别是get_preparation_dataprepare(这是针对Windows系统的),我们发现全局变量并没有被序列化。父进程的__main__重新导入看起来有点麻烦,但它不会运行任何代码,除了顶层的代码;甚至连if __name__ == '__main__'的部分也不会执行。所以只需保持主模块在导入时没有副作用。


当子进程启动时,你也可以防止主模块导入任何东西(这在Windows系统上特别有用,因为正如你所提到的,它不能进行分叉)。把main()和它的导入放到一个单独的模块中,这样启动脚本只包含:

if '__name__' == '__main__':
    from mainmodule import main
    main()

在子进程启动时,仍然有一个隐含的import site。这个导入会进行重要的初始化,我认为mp.forking没有简单的方法来禁用它,但我也不认为它会消耗太多资源。

撰写回答