Python 对修饰函数使用多处理会导致PicklingError
我正在尝试基于Python 对修饰函数使用多处理会导致PicklingError,python,multiprocessing,Python,Multiprocessing,我正在尝试基于多处理库编写一个方便的函数,它接受任何函数和参数,并使用多个进程运行该函数。我正在导入以下文件“MultiProcFunctions.py”: import multiprocessing from multiprocessing import Manager def MultiProcDecorator(f,*args): """ Takes a function f, and formats it so that results are saved to a
多处理
库编写一个方便的函数,它接受任何函数和参数,并使用多个进程运行该函数。我正在导入以下文件“MultiProcFunctions.py”:
import multiprocessing
from multiprocessing import Manager
def MultiProcDecorator(f,*args):
"""
Takes a function f, and formats it so that results are saved to a shared dict
"""
def g(procnum,return_dict,*args):
result = f(*args)
return_dict[procnum] = result
return g
def MultiProcFunction(f,n_procs,*args):
"""
Takes a function f, and runs it in n_procs with given args
"""
manager = Manager()
return_dict = manager.dict()
jobs = []
for i in range(n_procs):
p = multiprocessing.Process( target = f, args = (i,return_dict) + args )
jobs.append(p)
p.start()
for proc in jobs:
proc.join()
return dict(return_dict)
以下是我运行的代码:
from MultiProcFunctions import *
def sq(x):
return [i**2 for i in x]
g = MultiProcDecorator(sq)
if __name__ == '__main__':
result = MultiProcFunction(g,2,[1,2,3])
我得到以下错误:PicklingError:无法pickle:未将其作为MultiProcFunctions.g找到
如果我对g
使用以下定义,则一切正常:
def g(procnum,return_dict,x):
result = [i**2 for i in x]
return_dict[procnum] = result
为什么g
的两个定义不同,我能做些什么让原来的g
定义“起作用”这是因为g
实际上是定义为多过程函数中的嵌套函数的,这意味着它实际上不能从该模块的顶层导入,这意味着它不能正确地pickle。现在,我们实际上在\uuuu main\uuuu
模块的顶层非常清楚地定义了g
,但是,当我们这样做时:
g = MultiProcDecorator(sq)
所以,它真的应该是可挑选的。我们可以通过显式地将g
的模块设置为“\uu主模块”
,使其工作:
这将允许酸洗过程工作,因为它将在\uuuuu main\uuuuu
中查找g
的定义,其中它是在顶层定义的,而不是仅在嵌套范围中定义的多过程函数
编辑:
请注意,您还可以在装饰器本身中进行更改:
def MultiProcDecorator(f,*args):
"""
Takes a function f, and formats it so that results are saved to a shared dict
"""
def g(procnum,return_dict,*args):
result = f(*args)
return_dict[procnum] = result
g.__module__ = "__main__"
return g
这对您来说可能更有意义,因为此装饰程序严格地用于多处理
目的。尝试似乎只适用于Python 2。在Python 3中尝试时,出现以下错误:
pickle.PicklingError:无法pickle:它与\uuuu main\uuuuu.orig\u fn对象不同
我通过worker's init中的“装饰”函数解决了这个问题:
from functools import wraps
import sys
def worker_init(fn, *args):
@wraps(fn)
def wrapper(x):
# wrapper logic
pass
setattr(sys.modules[fn.__module__], fn.__name__, wrapper)
pool = mp.Pool(initializer=worker_init, initargs=[orig_fn, *args])
# ...
代码示例中是否有任何内容仍然会导致错误?如果你去掉它,它可能会帮助你找到问题的答案。用芹菜这样的现成解决方案有什么错?普伊塞克,不知道芹菜,现在正在研究它。APerson:我编辑了这个问题,所以它包含了尽可能少的代码,也许这样可以更容易地看到发生了什么。@kyphos它应该适合您的用例。如果你想在将来吸引某人的注意力,请确保在他们的名字前面加上“@;”)。在您的示例中,g
是MultiProcessingDecorator
的本地。pickle
的限制之一是它只序列化全局定义的函数。要克服这个问题,您可以将多处理器装饰器
作为一个类,并实现pickle
。很好!我找了好一阵子合适的解决办法,这一个做得很好!
from functools import wraps
import sys
def worker_init(fn, *args):
@wraps(fn)
def wrapper(x):
# wrapper logic
pass
setattr(sys.modules[fn.__module__], fn.__name__, wrapper)
pool = mp.Pool(initializer=worker_init, initargs=[orig_fn, *args])
# ...