Python 3.6.5出现multiprocessing PicklingError,3.6.1无此问题
解决Python 3.6.5中multiprocessing的PicklingError问题
我之前处理过好多这类因Python小版本差异引发的pickling问题,你的情况正好踩中了Python 3.6系列的一个细节变化——从3.6.2开始,multiprocessing模块对pickle序列化的校验变得更严格了,而3.6.1还没启用这些限制,这就导致你的代码在旧版本能跑,新版本直接报错。
核心原因
multiprocessing启动子进程时,需要把要执行的任务对象(比如目标函数、传递的参数)序列化(pickle)后传给子进程。3.6.5里对「哪些对象能被安全pickle」的检查比3.6.1严格得多,常见的触发场景有这几种:
- 用了lambda表达式或者嵌套函数:旧版本可能侥幸能序列化这些对象,但新版本直接判定它们无法被跨进程安全传递
- 自定义类定义在函数内部:子进程无法从模块中导入这个类,序列化时直接失败
- 类使用了
__slots__但没正确处理序列化逻辑,或者依赖了闭包中的变量
具体解决方案
针对这些场景,给你几个实用的修复方向:
1. 替换lambda或嵌套函数
把原本用lambda或嵌套函数实现的逻辑,移到模块级别定义成普通函数。比如:
原来的错误代码(3.6.1能跑,3.6.5报错):
from multiprocessing import Process def run_task(): # 嵌套函数或lambda在这里 p = Process(target=lambda: print("Processing task...")) p.start() p.join() if __name__ == "__main__": run_task()
改成模块级函数:
from multiprocessing import Process # 把逻辑移到模块顶层 def process_task(): print("Processing task...") def run_task(): p = Process(target=process_task) p.start() p.join() if __name__ == "__main__": run_task()
2. 确保自定义类在模块级别定义
如果你的代码里用到了自定义类,绝对不要把类定义在函数内部,子进程无法找到这个类的定义,必然触发PicklingError。比如把:
def main(): class MyTask: def __init__(self, data): self.data = data def run(self): print(self.data) p = Process(target=MyTask("test").run) p.start()
改成:
# 类定义在模块顶层 class MyTask: def __init__(self, data): self.data = data def run(self): print(self.data) def main(): p = Process(target=MyTask("test").run) p.start()
3. 用更健壮的序列化工具(可选)
如果实在没法调整代码结构,可以尝试用dill替代默认的pickle,它支持序列化更多Python对象(比如嵌套函数、lambda)。先安装dill:
pip install dill
然后在代码中替换multiprocessing的默认序列化器:
import multiprocessing as mp import dill # 替换默认的pickle为dill mp.reduction.ForkingPickler = dill.Pickler mp.reduction.dump = dill.dump
不过这个方法属于「曲线救国」,建议优先调整代码结构,避免依赖非标准序列化工具。
4. 检查参数中的对象引用
如果是传递给子进程的参数触发了错误,要确保这些参数都是模块级别的对象,或者能被子进程正确导入的对象,不要传递包含闭包变量的对象。
内容的提问来源于stack exchange,提问作者Rhys
相关产品推荐
相关产品推荐

