我正在尝试编写一个基于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 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: Can't pickle <function g at 0x01BD83B0>: it's not found as MultiProcFunctions.g
如果我使用g
的以下定义,那么一切都很好:
def g(procnum,return_dict,x):
result = [i**2 for i in x]
return_dict[procnum] = result
为什么g
的两个定义不同,有什么办法可以让原始g
定义“工作”?
答案 0 :(得分:2)
这种情况正在发生,因为g
实际上被定义为MultiProcFunctions
中的嵌套函数,这意味着它实际上不能从该模块的顶层导入,这意味着它赢了&# 39;酸洗得恰到好处。现在,我们在g
模块的顶层实际上非常清楚地定义了__main__
,但是当我们这样做时:
g = MultiProcDecorator(sq)
所以,应该可以选择。我们可以通过明确将__module__
g
"__main__"
设为g = MultiProcDecorator(sq)
g.__module__ = "__main__" # Fix the __module__
来使其发挥作用:
g
这将允许酸洗过程正常工作,因为它将在__main__
中查找MultiProcFunctions
的定义,其中定义在顶级,而不是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
,它只在嵌套范围内定义。
修改强>
请注意,您也可以在装饰器本身进行更改:
multiprocessing
这可能对你更有意义,因为这个装饰器严格意味着用于{{1}}目的。
答案 1 :(得分:1)
尝试dano's trick似乎只适用于Python 2.在Python 3中尝试时,我收到以下错误:
pickle.PicklingError:不能挑选
<function serialize at 0x7f7a1ac1fd08>
:它与 main 不同的对象.orig_fn
我通过&#34;装饰&#34;解决了这个问题。来自worker的初始函数:
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])
# ...