Python multiprocessing:apply_async调用类方法与传递对象问题
多进程apply_async调用类方法及传递对象参数的问题解决
核心问题分析
多进程间存在内存隔离,子进程操作的是主进程对象的副本,修改副本不会直接同步到主进程;另外,Windows系统的spawn模式下,实例方法、不可序列化对象(如mp.Pool)的传递会导致任务无法执行。
一、调用类方法的修改方案
问题原因
直接传递c1.foo作为目标函数时,在spawn模式下无法被正确序列化,导致子进程无法执行该方法。
修改后代码
import multiprocessing as mp class myClass(): def __init__(self, id): self.id = id self.val = 1.0 self.pool = None def callback(self, obj): self.val = obj.val def foo(self, new_val): print('foo passed with', new_val) self.val = new_val return self if __name__ == '__main__': c1 = myClass('c1') c1.pool = mp.Pool(processes=1) # 改为传递类方法+实例作为参数,避免序列化问题 c1.pool.apply_async(myClass.foo, args=(c1, 2.0, ), callback=c1.callback).wait() c1.pool.close() c1.pool.join() print('c1.val:', c1.val)
解释
通过myClass.foo明确指定类方法,同时将实例c1作为第一个参数传入,解决实例方法序列化的问题。子进程执行方法后修改副本的val并返回,主进程的callback方法将原实例的val更新为副本的val,得到预期结果。
二、传递对象作为参数的修改方案
问题原因
原代码中myClass包含mp.Pool类型的pool属性,而Pool对象不可被序列化,导致传递c1作为参数时序列化失败,子进程无法执行任务。
修改后代码
import multiprocessing as mp class myClass(): def __init__(self, id): self.id = id self.val = 1.0 self.pool = None def __getstate__(self): # 序列化时移除不可被pickle的pool属性 state = self.__dict__.copy() del state['pool'] return state def __setstate__(self, state): # 反序列化时恢复属性,pool设为None self.__dict__.update(state) self.pool = None def callback(self, obj): self.val = obj.val def foo(obj, new_val): print('foo passed with', new_val) obj.val = new_val return obj if __name__ == '__main__': c1 = myClass('c1') c1.pool = mp.Pool(processes=1) c1.pool.apply_async(foo, args=(c1, 2.0, ), callback=c1.callback).wait() c1.pool.close() c1.pool.join() print('c1.val:', c1.val)
解释
通过__getstate__和__setstate__方法控制对象的序列化过程,移除不可序列化的pool属性,确保c1能被正常传递到子进程。子进程修改副本的val后返回,主进程的callback同步更新原实例的val,得到预期结果。
内容的提问来源于stack exchange,提问作者Saad
相关产品推荐
相关产品推荐

