2010-09-08 74 views
26

我有一个相当复杂的Python对象,我需要在多个进程之间共享。我使用multiprocessing.Process启动这些进程。当我与multiprocessing.Queuemultiprocessing.Pipe共享一个对象时,它们共享就好了。但是,当我尝试与其他非多处理模块对象共享一个对象时,似乎Python会分叉这些对象。真的吗?在Python进程之间共享一个复杂的对象?

我尝试使用multiprocessing.Value。但我不确定这种类型应该是什么?我的对象类叫做MyClass。但是,当我尝试multiprocess.Value(MyClass, instance),它失败:

TypeError: this type has no size

任何想法是怎么回事?

+1

相关:http://stackoverflow.com/questions/659865/python-multiprocessing-sharing-a-large-read-only-object-between-processes – tokland 2010-09-08 21:18:50

回答

23

您可以使用Python的多处理“经理”类和您定义的代理类做到这一点。从Python文档: http://docs.python.org/library/multiprocessing.html#proxy-objects

你想要做的是什么定义您的自定义对象的代理类,然后共享使用“远程管理”的对象 - 看看在同一个链接的文档页面的例子为“远程管理器”文档显示如何共享远程队列。你将会做同样的事情,但是你对your_manager_instance.register()的调用将会在你的自变量列表中包含你的自定义代理类。

通过这种方式,你要创建一个服务器共享一个自定义代理自定义对象。您的客户需要访问服务器(同样,请参阅有关如何设置客户端/服务器访问远程队列的优秀文档示例,但不共享队列,您将共享访问您的特定类)。

+3

这个问题的代码帮助补充了我的文档页面。这是一个自定义类的例子。 http://stackoverflow.com/questions/11951750/sharing-object-class-instance-in-python-using-managers – EarlCrapstone 2013-11-29 06:32:11

15

经过大量的研究和测试后,我发现“经理”在非复杂的对象级别执行此项工作。

下面所示inst在进程之间共享该对象的代码,这意味着属性的instvar当子进程改变其外部改变。

from multiprocessing import Process, Manager 
from multiprocessing.managers import BaseManager 

class SimpleClass(object): 
    def __init__(self): 
     self.var = 0 

    def set(self, value): 
     self.var = value 

    def get(self): 
     return self.var 


def change_obj_value(obj): 
    obj.set(100) 


if __name__ == '__main__': 
    BaseManager.register('SimpleClass', SimpleClass) 
    manager = BaseManager() 
    manager.start() 
    inst = manager.SimpleClass() 

    p = Process(target=change_obj_value, args=[inst]) 
    p.start() 
    p.join() 

    print inst     # <__main__.SimpleClass object at 0x10cf82350> 
    print inst.get()    # 100 

好了,上面的代码是足够如果你只需要共享简单对象

为什么不复杂吗?由于如果你的对象是嵌套(内部目标对象),它可能会失败

from multiprocessing import Process, Manager 
from multiprocessing.managers import BaseManager 

class GetSetter(object): 
    def __init__(self): 
     self.var = None 

    def set(self, value): 
     self.var = value 

    def get(self): 
     return self.var 


class ChildClass(GetSetter): 
    pass 

class ParentClass(GetSetter): 
    def __init__(self): 
     self.child = ChildClass() 
     GetSetter.__init__(self) 

    def getChild(self): 
     return self.child 


def change_obj_value(obj): 
    obj.set(100) 
    obj.getChild().set(100) 


if __name__ == '__main__': 
    BaseManager.register('ParentClass', ParentClass) 
    manager = BaseManager() 
    manager.start() 
    inst2 = manager.ParentClass() 

    p2 = Process(target=change_obj_value, args=[inst2]) 
    p2.start() 
    p2.join() 

    print inst2     # <__main__.ParentClass object at 0x10cf82350> 
    print inst2.getChild()   # <__main__.ChildClass object at 0x10cf6dc50> 
    print inst2.get()    # 100 
    #good! 

    print inst2.getChild().get() # None 
    #bad! you need to register child class too but there's almost no way to do it 
    #even if you did register child class, you may get PicklingError :) 

我觉得这种行为的主要原因是因为Manager只是一个直板建立在像管道低级别的通信工具之上/队列。

因此,这种做法是不以及建议多处理情况。它总是更好,如果你可以使用低级别的工具,如锁/信号灯/管材/队列或高层次的工具,如Redis的队列Redis的发布/订阅复杂的使用情况下(只是我的建议笑)。

+0

如何共享一个复杂的对象? – 2017-09-21 08:49:26

0

为了节省一些头痛与共享的资源,你可以尝试收集需要在由例如映射函数的返回语句访问单身资源数据pool.imap_unordered,然后进一步的循环中获取部分结果对其进行处理:

for result in in pool.imap_unordered(process_function, iterable_data): 
    do_something(result) 

如果没有得到返回如此多的数据,则可能不会在这样的开销。

2

这里是我为此所做的一个python包(在进程之间共享复杂对象)。

的git:https://github.com/dRoje/pipe-proxy

的想法是你的对象创建一个代理,并把它传递给一个过程。然后你使用代理就像你有一个对原始对象的引用。尽管你只能使用方法调用,所以访问对象变量时会抛出setter和getters。

假设我们有一个名为“示例”的对象,创建代理和代理监听器很简单:

from pipeproxy import proxy 
example = Example() 
exampleProxy, exampleProxyListener = proxy.createProxy(example) 

现在您发送的代理到另一个进程。

p = Process(target=someMethod, args=(exampleProxy,)) p.start() 

使用它在其他进程中,你会使用原来的对象(例如):

def someMethod(exampleProxy): 
    ... 
    exampleProxy.originalExampleMethod() 
    ... 

但是,你要听它的主要工序:

exampleProxyListener.listen() 

阅读更多并在这里找到示例:

http://matkodjipalo.com/index.php/2017/11/12/proxy-solution-python-multiprocessing/