类实例字典的多处理

时间:2017-02-07 23:03:57

标签: python-3.x oop multiprocessing

在下面的通用示例中,我使用Foobar_Collection来管理Foo个实例的字典。另外,Foobar_Collection带有一种方法,可以按顺序调用myMethod()所有项目共享的Foo。它到目前为止工作正常。但是,我想知道我可以利用 多处理,以便run_myMethodForAllfoobars()可以划分几个实例块的工作?实例方法彼此“独立”(我认为这种情况被称为令人尴尬的并行)。任何帮助都会很棒!

class Foobar_Collection(dict):
    def __init__(self, *arg, **kw):
        super(Foobar_Collection, self).__init__(*arg,**kw)
    def foobar(self,*arg,**kw):
        foo = Foo(*arg,**kw)
        self[foo.name] = foo
        return foo

    def run_myMethodForAllfoobars(self):
        for name in self:
            self[name].myMethod(10)
        return None


class Foo(object):
    def __init__(self,name):
        self.name = name
        self.result = 0
    # just some toy example method    
    def myMethod(self,x):
        self.result += x
        return None

Foobar = Foobar_Collection()
Foobar.foobar('A')
Foobar.foobar('B')
Foobar.foobar('C')
Foobar.run_myMethodForAllfoobars()

1 个答案:

答案 0 :(得分:1)

可以使用multiprocessing来解决这种情况,但这并不好,因为你尝试并行化的方法对于它的副作用很有用,而不是它的回报价值。这意味着您需要在两个方向上序列化Foo对象(将其发送到子进程,然后再发送修改后的版本)。如果您的真实对象比示例中的Foo对象更复杂,那么复制对象的所有数据的开销可能会比在一个进程中执行所有操作更慢。

def worker(foo):
    foo.myMethod(10)
    return foo

class Foobar_Collection(dict):
    #...

    def run_myMethodForAllfoobars(self):
        with multiprocessing.Pool() as pool:
            results = pool.map(worker, self.values())
        self.update((foo.name, foo) for foo in results)

更好的设计可能只允许您序列化进行计算所需的信息。在您的示例中,Foo对象中唯一需要的是result(您将添加10个),您可以在不绕过对象的其余部分的情况下提取和处理它:

def worker(num):
    return num + 10

class Foobar_Collection(dict):
    #...

    def run_myMethodForAllfoobars(self):
        with multiprocessing.Pool() as pool:
            results = pool.map(worker, (foo.result for foo in self.values()))
        for foo, new_result in zip(self.values(), results):
            foo.result = new_result

现在很明显,这实际上不再对myMethod个对象运行foo(尽管它相当于这样做)。如果你不能像这样将方法与对象分离,那么可能很难获得良好的性能。