使用multiprocessing并行处理对象实例时属性未更新问题排查
Python多进程更新对象属性失效问题分析与解决
问题重现
串行执行时,对象的bar属性能被正确设置为1.0:
class Foo: def __init__(self): self.bar = None def put_bar(self): self.bar = 1.0 if __name__ == "__main__": instances = [Foo() for _ in range(100)] for instance in instances: instance.put_bar() # 输出1.0 print(instances[0].bar)
但改用multiprocessing.Pool并行处理后,原对象的bar属性仍为None:
import os from multiprocessing import Pool class Foo: def __init__(self): self.bar = None def put_bar(self): self.bar = 1.0 def worker(instance): return instance.put_bar() if __name__ == "__main__": instances = [Foo() for _ in range(100)] with Pool(os.cpu_count()) as pool: pool.map(worker, (instance for instance in instances)) # 输出None print(instances[0].bar)
问题根源
Python的多进程采用内存隔离机制:子进程会复制主进程的对象副本进行操作,而非直接修改主进程中的原对象。你的worker函数调用instance.put_bar()后,修改的是子进程里的对象副本,主进程中的原对象完全不受影响。另外put_bar()方法没有返回修改后的对象,pool.map()拿到的只是一堆None,自然无法更新原列表里的实例。
解决方案
修改worker函数,让它返回修改后的对象实例,再用pool.map()的结果替换原列表中的对象:
import os from multiprocessing import Pool class Foo: def __init__(self): self.bar = None def put_bar(self): self.bar = 1.0 def worker(instance): instance.put_bar() return instance # 返回修改后的对象 if __name__ == "__main__": instances = [Foo() for _ in range(100)] with Pool(os.cpu_count()) as pool: # 用返回的修改后的对象替换原列表 instances = pool.map(worker, instances) # 输出1.0 print(instances[0].bar)
补充说明
如果你的Foo类包含大型数据,复制对象会带来额外的内存开销,此时可以考虑使用multiprocessing.Manager创建可共享的对象,或者将属性改为共享内存类型(如multiprocessing.Value)。但对于大多数场景,直接返回修改后的对象是最简单高效的方案。
内容的提问来源于stack exchange,提问作者abc
相关产品推荐
相关产品推荐

