Python3.5.2与3.6.3多进程Pickle报错求助:无法序列化MyClass实例
为什么Python 3.6.3中multiprocessing无法pickle自定义类实例?
这个问题大概率和Python 3.5到3.6之间pickle机制的严格性提升以及multiprocessing对序列化的要求变化有关,具体可以从这几个方向排查:
可能的原因
1. 自定义类的pickle实现不符合3.6的规范
Python 3.6对pickle的校验逻辑做了调整,如果你在MyClass中自定义了__reduce__、__getstate__或__setstate__方法,在3.5中能“侥幸”通过的不规范实现,到3.6会被严格拦截。比如:
__reduce__返回的元组中,第一个元素不是可全局导入的类/函数(比如是局部作用域内定义的类)__getstate__返回的对象包含无法被pickle序列化的内部状态
2. 类的模块可见性问题
如果MyClass是定义在函数内部或者动态生成的模块中,在Python 3.6的spawn启动方式下(Windows默认是spawn,Unix下如果显式指定也会用),子进程需要重新导入模块才能重建类对象。而3.5中如果用fork方式(Unix默认),会直接复制父进程的内存空间,不需要重新导入,所以不会暴露这个问题。
3. Pickle协议版本的默认变化
Python 3.6默认使用的pickle协议版本(协议4)比3.5的默认版本(协议3)有更多限制,如果你的类依赖低版本协议的宽松特性,就会触发错误。
解决办法
1. 检查并修复自定义类的pickle实现
确保MyClass的序列化逻辑符合标准:
- 如果用
__reduce__,返回的元组第一个元素必须是可在子进程中通过导入获取的类/函数 - 如果用
__getstate__,返回的字典只包含可序列化的对象(比如避免包含文件句柄、网络连接等)
2. 确保类在顶层模块定义
把MyClass移到主模块的顶层,或者一个可以被子进程正常导入的模块中,避免在函数内部定义类。
3. 显式指定低版本pickle协议
在序列化时指定协议版本为3,兼容3.5的行为:
import pickle pickle.dumps(my_instance, protocol=3)
如果是用multiprocessing.Pool,可以通过自定义初始化函数来设置:
import multiprocessing as mp import pickle def init_pool(): pickle.HIGHEST_PROTOCOL = 3 if __name__ == "__main__": pool = mp.Pool(initializer=init_pool) # 后续调用pool的方法
4. 替换为更灵活的序列化库
如果默认pickle满足不了需求,可以用dill或cloudpickle替代,它们支持更多类型的序列化(比如局部类、lambda等):
import multiprocessing as mp from multiprocessing import reduction import dill def init_dill(): # 替换multiprocessing的默认pickler reduction.ForkingPickler = dill.Pickler if __name__ == "__main__": pool = mp.Pool(initializer=init_dill) # 你的业务代码
内容的提问来源于stack exchange,提问作者sulo
相关产品推荐
相关产品推荐

