使用multiprocess包时遭遇Can't pickle local object错误求助
解决multiprocessing调用类方法时的Pickle错误
结合你的代码和报错信息,我来拆解一下你遇到的问题和对应的解决方案:
问题根源拆解
- 参数传递格式错误:你调用
pool.apply_async(f, pop)时,第二个参数pop是单个数值,但apply_async要求参数必须是元组类型,直接传单个值会被当成多个参数解析,这本身就会引发错误,更别说后续的pickle问题了。 - 局部对象无法被Pickle序列化:报错里的
Can't pickle local object 'exhaust.__init__.<local object>'说明你的exhaust类(或者create_new_population方法所属的类)是定义在某个函数内部的局部类。pickle无法序列化局部作用域中的对象——因为子进程无法从全局模块中找到这个类的定义,自然也就无法反序列化。
分步解决方案
第一步:修正参数传递方式
先把apply_async的参数改成元组格式,这是基础要求:
# 把pop包装成元组,注意末尾的逗号不能丢 self.current_generation = [pool.apply_async(f, (pop,)) for _ in range(8)]
第二步:解决局部对象的Pickle问题
针对类定义在局部作用域的情况,有两种常用解决思路:
思路1:将类移到顶层模块
最直接的办法是把你的exhaust类(或者包含create_new_population的类)从函数内部移到Python文件的顶层(也就是不在任何函数、类的嵌套结构里)。这样子进程可以通过import找到类的定义,pickle就能正常序列化实例方法了。
思路2:用顶层函数包装实例方法
如果无法移动类的定义,可以写一个顶层的包装函数,把实例和方法参数传递进去,绕开局部对象的pickle限制:
# 定义在文件顶层,不要嵌套在任何函数/类里 def create_new_population_wrapper(instance, pop_size): return instance.create_new_population(pop_size)
然后在你的类中这样调用进程池:
from functools import partial # 绑定当前实例到包装函数 wrapper_func = partial(create_new_population_wrapper, self) pop = self.pop_size // 8 # 建议用整数除法,避免浮点数导致的参数问题 self.current_generation = [pool.apply_async(wrapper_func, (pop,)) for _ in range(8)] # 最后别忘了获取异步任务的结果,apply_async返回的是AsyncResult对象 self.current_generation = [res.get() for res in self.current_generation]
额外提示
- 如果你的
create_new_population方法依赖实例的状态(比如self里的属性),要确保这些状态是可pickle的,否则还是会触发序列化错误。 - 如果你频繁遇到pickle相关的多进程问题,可以考虑使用
pathos库(它用dill替代pickle,支持更多类型的序列化),不过这属于第三方库,需要先安装:pip install pathos。
内容的提问来源于stack exchange,提问作者Panos Kalatzantonakis
相关产品推荐
相关产品推荐

