使用multiprocessing Pool.map时类变量变为空的问题咨询
问题根源
这个问题是Python multiprocessing 模块的进程内存隔离特性导致的,分两种常见场景:
- 如果你使用的是Windows、macOS 10.15+系统,默认进程启动模式为
spawn:子进程启动时会重新导入所有依赖模块,你在父进程运行时修改的Utils._raw_data属于运行时状态,不会被带到子进程的导入环境,子进程里的Utils类会重新执行初始化逻辑,_raw_data自然回到初始的空defaultdict状态。 - 如果你使用的是Linux系统,默认进程启动模式为
fork:仅当你在**创建Pool实例之后才修改Utils._raw_data**的情况下才会出现该问题,因为fork操作只会复制父进程创建Pool时刻的内存快照,之后父进程修改的变量不会同步到已经创建的子进程内存空间中。
解决方案
有三种常用修复方案,兼容性从高到低排列:
方案1:将数据作为参数传递给子进程任务(最推荐)
避免在子进程中读取全局/类变量,直接把Utils.raw_data()的结果作为参数和任务一起传递,不需要考虑平台差异,性能也最高:
# 父类方法修改为接收raw_data参数 class Parent: ... def evaluate_without_prefix(self, devices, raw_data): results = [] for network1, network2 in itertools.product(raw_data[devices[0]], raw_data[devices[1]]): if network1.subnet_of(network2): results.append((devices[0], network1, devices[1], network2)) if network2.subnet_of(network1): results.append((devices[1], network2, devices[0], network1)) return results # 子类调用时打包参数 class Child(Parent): ... def execute(self): raw_data = Utils.raw_data() devices = list(itertools.combinations(list(raw_data.keys()), 2)) # 把raw_data和每个devices组合成任务参数 task_args = [(d, raw_data) for d in devices] pool = Pool(os.cpu_count() - 1) # 用starmap传递多参数 results = pool.starmap(super().evaluate_without_prefix, task_args) pool.close() pool.join() return results
方案2:使用进程间共享容器
用multiprocessing自带的共享数据结构替换普通字典,所有进程读写同一份数据:
from multiprocessing import Manager from collections import defaultdict class Utils: _manager = Manager() _raw_data = _manager.dict() @classmethod def raw_data(cls): return dict(cls._raw_data) @classmethod def set_raw_data(cls, key, data): cls._raw_data[key] = data
方案3:调整执行顺序(仅适配Linux fork模式)
如果你的运行环境是Linux默认fork模式,确保所有写入Utils._raw_data的操作都在创建Pool实例之前完成,fork出来的子进程就会直接继承父进程修改后的类变量状态。
内容的提问来源于stack exchange,提问作者ReverseEngineer
相关产品推荐
相关产品推荐

