Jupyter Notebook中multiprocessing Manager适配spawn/forkserver启动异常问题
异常成因
- 不同多进程启动模式的内存继承逻辑有本质差异:
- fork模式会直接复制父进程的全部内存空间,子进程可以直接继承父进程中创建的Manager共享对象代理,不需要重复初始化,因此代码可以正常运行。
- spawn和forkserver模式启动子进程时,会重新导入父进程的执行模块,模块顶层的所有代码都会在子进程中重新执行一遍。你当前代码把
Manager()实例化、共享字典创建、子进程启动逻辑都写在了模块全局作用域,子进程导入时会重复创建新的Manager实例和共享字典,和父进程的共享对象完全不是同一个,代理对象失效导致运行失败,严重时还会触发无限创建子进程的崩溃问题。
- 额外隐藏问题:当前代码主进程在启动子进程后直接读取共享字典,没有等待子进程执行完成,即使启动模式没有问题,也大概率出现
KeyError。
解决方案
核心原则是所有涉及多进程初始化、共享对象创建、子进程启动的逻辑,都必须放到if __name__ == '__main__'的判断块中,避免子进程导入模块时重复执行这些代码,同时增加子进程等待逻辑保证数据写入完成。
修复后的代码如下:
from multiprocessing import Process, Manager class WorkerProcess(Process): def __init__(self, shared_results_dict): super(WorkerProcess, self).__init__() self.shared_results_dict = shared_results_dict def run(self): self.shared_results_dict['a'] = 3 if __name__ == '__main__': # 共享对象创建和子进程启动逻辑全部放到主进程判断块内 manager = Manager() shared_results_dict = manager.dict() subproc = WorkerProcess(shared_results_dict) subproc.daemon = True subproc.start() # 等待子进程执行完成再读取数据 subproc.join() print(shared_results_dict['a'])
内容的提问来源于stack exchange,提问作者StatsNoob
相关产品推荐
相关产品推荐

