我试图使用multiprocessing的Pool.map()函数来同时划分工作。当我使用以下代码时,它工作得很好:

import multiprocessing

def f(x):
    return x*x

def go():
    pool = multiprocessing.Pool(processes=4)        
    print pool.map(f, range(10))


if __name__== '__main__' :
    go()

然而,当我在更面向对象的方法中使用它时,它就不起作用了。它给出的错误信息是:

PicklingError: Can't pickle <type 'instancemethod'>: attribute lookup
__builtin__.instancemethod failed

这发生时,以下是我的主程序:

import someClass

if __name__== '__main__' :
    sc = someClass.someClass()
    sc.go()

下面是我的someClass类:

import multiprocessing

class someClass(object):
    def __init__(self):
        pass

    def f(self, x):
        return x*x

    def go(self):
        pool = multiprocessing.Pool(processes=4)       
        print pool.map(self.f, range(10))

有人知道问题是什么吗,或者有什么简单的解决方法吗?


当前回答

上面parisjohn的解决方案对我很有效。此外,代码看起来很干净,易于理解。在我的例子中,有几个函数要使用Pool调用,所以我在下面修改了parisjohn的代码。我使__call__能够调用几个函数,函数名在go()的参数dict中传递:

from multiprocessing import Pool
class someClass(object):
    def __init__(self):
        pass
    
    def f(self, x):
        return x*x
    
    def g(self, x):
        return x*x+1    

    def go(self):
        p = Pool(4)
        sc = p.map(self, [{"func": "f", "v": 1}, {"func": "g", "v": 2}])
        print sc

    def __call__(self, x):
        if x["func"]=="f":
            return self.f(x["v"])
        if x["func"]=="g":
            return self.g(x["v"])        

sc = someClass()
sc.go()

其他回答

对此,一个潜在的简单解决方案是切换到使用multiprocessing.dummy。这是一个基于线程的多处理接口实现,在Python 2.7中似乎没有这个问题。我在这方面没有太多经验,但是这个快速的导入更改允许我在类方法上调用apply_async。

一些关于multi - processing.dummy的好资源:

https://docs.python.org/2/library/multiprocessing.html#module-multiprocessing.dummy

http://chriskiehl.com/article/parallelism-in-one-line/

在这个简单的例子中,someClass。F没有从类中继承任何数据,也没有向类中附加任何数据,一个可能的解决方案是将F分离出来,这样它就可以被pickle:

import multiprocessing


def f(x):
    return x*x


class someClass(object):
    def __init__(self):
        pass

    def go(self):
        pool = multiprocessing.Pool(processes=4)       
        print pool.map(f, range(10))

我遇到了同样的问题,但发现有一个JSON编码器可以用来在进程之间移动这些对象。

from pyVmomi.VmomiSupport import VmomiJSONEncoder

用这个来创建你的列表:

jsonSerialized = json.dumps(pfVmomiObj, cls=VmomiJSONEncoder)

然后在mapped函数中,使用this来恢复对象:

pfVmomiObj = json.loads(jsonSerialized)

为什么不使用单独的函数?

def func(*args, **kwargs):
    return inst.method(args, kwargs)

print pool.map(func, arr)

上面parisjohn的解决方案对我很有效。此外,代码看起来很干净,易于理解。在我的例子中,有几个函数要使用Pool调用,所以我在下面修改了parisjohn的代码。我使__call__能够调用几个函数,函数名在go()的参数dict中传递:

from multiprocessing import Pool
class someClass(object):
    def __init__(self):
        pass
    
    def f(self, x):
        return x*x
    
    def g(self, x):
        return x*x+1    

    def go(self):
        p = Pool(4)
        sc = p.map(self, [{"func": "f", "v": 1}, {"func": "g", "v": 2}])
        print sc

    def __call__(self, x):
        if x["func"]=="f":
            return self.f(x["v"])
        if x["func"]=="g":
            return self.g(x["v"])        

sc = someClass()
sc.go()