Python多进程错误

时间:2014-12-28 20:10:25

标签: python python-2.7 multiprocessing pickle

我遇到了多进程的问题,下面是我用来执行测试的代码:

import multiprocessing


class Test():
    def __init__(self):
        pass

    def add(self,x,y):
        self.x = x
        self.y = y
        return self.x + self.y


class Worker(Test):
    def do_me(self,x,y):
        return self.add(x,y)


if __name__ == '__main__':

    job = Worker()

    # #single process
    # x = 1
    # y = 9
    # result = job.do_me(x,y)
    # print "%2d +%2d = %2d "%(x,y,result)

    #multiprocess
    x = [1,2,3]
    y = [9,7,5]

    pool = multiprocessing.Pool(processes=4)
    retults = [ pool.map(job.do_me, ((x[i], y[i]),)) for i in range(len(x)) ]
    print results

对于单个过程,它将正常工作。但是,对于多进程,它没有。错误消息是:

cPickle.PicklingError: Can't pickle <type 'instancemethod'>: attribute lookup __builtin__.instancemet hod failed
我在这里搜索,但我不太了解机制。有人能给我更多帮助吗?欢呼声。

1 个答案:

答案 0 :(得分:2)

正如错误所示,您无法挑选实例方法。问题是这一行:

pool.map(job.do_me, ((x[i], y[i]),)) for i in range(len(x))

这背后的机制是当map函数将函数(第一个参数)发送给所有工作者时,它必须以某种方式将其序列化为数据,因此它使用一种称为的机制pickling。还有其他机制,这是Python中非常常见的机制。

当它试图挑选一个实例方法(特别是方法do_me,类型为Worker的实例)并将其发送到池中时(让工人知道他们采用什么方法&# 39;应该执行),它失败了。因为你不能腌制实例方法。

您可以通过将方法移动到模块级别(删除Worker类)来解决此问题:

def do_me(test_instance):
    return test_instance.add(x,y)

现在我们无法访问self,因为我们正在使用明确发送的test_instance,因此此方法不会绑定到{{ 1}}类了...或换句话说 - 这不再是实例方法。现在请确保在计划时重新考虑所有因素。

Test类应该在这个结构中有一些东西,以便将参数构造中的列表理解保持为Test简单:

pool.map

Adn然后这样称呼它:

class Test():
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def add(self,x,y):
        return self.x + self.y

完整代码:

results = pool.map(do_me, [Test(x[i], y[i]) for i in range(len(x))])

一些注意事项:

  1. import multiprocessing class Test(): def __init__(self, x, y): self.x = x self.y = y def add(self): return self.x + self.y def do_me(test_instance): return test_instance.add() if __name__ == '__main__': x = [1,2,3] y = [9,7,5] pool = multiprocessing.Pool(processes=4) results = pool.map(do_me, [Test(x[i], y[i]) for i in range(len(x))]) print results 已经返回pool.map

  2. list init 标识对象数据的标准位置(在您的情况下为x,y)。

  3. 函数__init__正在使用的函数应用于iterable的每个项目,因此它应该是单参数函数(您可以使用元组,但您必须将其解包)。