Python多进程:AttributeError: 无法pickle本地对象

7

我在一个类中有一个方法,可以返回一个参数可能会改变的函数。

这个接口函数接受两个参数:f 和它的 args。我想使用 mp.pool 来加速它的运行,但是出现了错误。

from multiprocessing import Pool
# from multiprocess import Pool
# from pathos.multiprocessing import ProcessingPool as Pool
import pickle
import dill


class Temp:
    def __init__(self, a):
        self.a = a

    def test(self):
        def test1(x):
            return self.a + x

        return test1


def InterfaceFunc(f, x):
    mypool = Pool(4)
    return list(mypool.map(f, x))


if __name__ == "__main__":
    t1 = Temp(1).test()
    x = [1, 2, 3, 1, 2]

    res1 = list(map(t1, x))
    print(res1)

    res2 = InterfaceFunc(t1, x)

它会引发相同的错误:

AttributeError: Can't pickle local object 'Temp.test.<locals>.test1'

我尝试了三种方法:

multiprocessing和dill可以一起做什么?

替换Python multiprocessing库中的pickle

Python Multiprocessing Pool Map:AttributeError:无法pickle本地对象

方法1、2:

 from multiprocess import Pool
 from pathos.multiprocessing import ProcessingPool as Pool

这会引发错误:

 File "E:\Users\ll\Anaconda3\lib\site-packages\dill\_dill.py", line 577, in _load_type
    return _reverse_typemap[name]
KeyError: 'ClassType'

Method3需要更改代码,但我不能简单地将该函数移出该类,因为我需要f作为接口的参数。

你有什么建议吗?我是一个缺乏经验的新手。


你的示例无法运行,这使得尝试解决方案更加困难。 - tdelaney
@tdelaney 抱歉,我之前犯了一个错误。我已经更改了代码,并且引发了一个异常。 - abcyunice
我不认为链接的问题回答了这个问题。在那里,OP可以将函数移动到模块级别,但这里不是这种情况,因为调用还涉及需要管理的状态。 - tdelaney
3个回答

8

Python无法pickle闭包,但你真正需要的是能够保留状态并且可以调用的东西。 __call__方法使类实例可调用,因此请使用它。

from multiprocessing import Pool

class TempTest1:

    def __init__(self, a):
        self.a = a

    def __call__(self, x):
        return self.a + x

class Temp:
    def __init__(self, a):
        self.a = a

    def test(self):
        return TempTest1(self.a)

def InterfaceFunc(f, x):
    mypool = Pool(4)
    return list(mypool.map(f, x))

if __name__ == "__main__":
    t1 = Temp(1).test()
    x = [1, 2, 3, 1, 2]

    res1 = list(map(t1, x))
    print(res1)

    res2 = InterfaceFunc(t1, x)
    print(res2)

1
谢谢您的建议。您能分享一些关于“Python无法pickle闭包”的文档吗?我在“https://www.python.org/”上找不到相关信息。 - Cloud Cho

1
有点晚了,但是将类函数(你想要的那个)传递到包装函数中对我很有帮助:
from multiprocessing import Pool

def myWorkFunc(load):
    return load["fu"](load["i"])

class Test():
    def __init__(self):
        self.a = 1

    def add_one(self, x):
        print('adding', x)
        return x + 1

    def do_something(self):
        loads = [{"i": i, "fu": self.add_one} for i in range(4)]
        with Pool(4) as mypool:
            return mypool.map(func=myWorkFunc, iterable=loads)

if __name__ == '__main__':
    T = Test()
    print(T.do_something())

0

我尝试了多种方法来处理这个错误,我认为最简单的方法是找到导致错误的文件,并将1替换为2。

  1. import pickle
  2. import dill as pickle

dill库扩展了pickle的功能,可以为您处理此错误。

祝你好运!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接