这个问题,出在主进程向新进程(子进程)传递的参数不可被序列化上,那么,只要传递的参数可以序列化,问题就不存在了(貌似是废话,但理解这句话至关重要)。
假设不可被pickle的类是Task,而task是一个不可被pickle的Task的实例化对象。
不论使用multiprocessing.Process()
还是multiprocessing.Pool()
,都是主进程向子进程的worker
传递参数,这些参数要确保是可序列化的即可。
worker(args)
要创建在if __name__ == __main__
之外,确保是在顶层(通俗理解就是def worker(args)前不能有空格,确保无缩进),否则会提示不可pickleworker
是在新进程中运行的,除了接受参数的过程涉及由主进程向新进程传递外,worker
的body部分与主进程没有半毛钱关系,也不在主进程中运行worker
传递的参数args
必须是可被序列化的,这点很容易做到错误方式
class Task:
def __init__(self,s):
self.s = s
def run(self):
pass
# 不可被pickle的对象,创建在主进程中,等待由主进程向新进程传递,这个过程一定涉及task的序列化
tasks = [Task(str(i)) for i in range(5)]
def worker(task):
task.run()
if __name__ == "__main__":
with multiprocessing.Pool() as pool:
# 因为tasks中的元素(具体的task)都是不可被pickle的,所以由主进程向新进程传递时,就会报错can't pickle
pool.map(worker, tasks)
正确代码
class Task:
def __init__(self,s):
self.s = s
def run(self):
pass
# 这里的s_list中的每一个元素,都是Python内置支持的类型,所以一定可被序列化
s_list = [str(i) for i in range(5)]
def worker(s):
# 重要区别,创建对象的过程是在worker中完成,而不是在主进程中
task = Task(s)
task.run()
if __name__ == "__main__":
with multiprocessing.Pool() as pool:
# 因为s_list中的元素(具体的s)都是可被pickle的,所以由主进程向新进程传递时,就不会报错can't pickle
pool.map(worker, s_list)