Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/279.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 对修饰函数使用多处理会导致PicklingError_Python_Multiprocessing - Fatal编程技术网

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])
# ...