2016-05-16 59 views
1

下面是一个简单塞奇纳罗:更新相同的实例变量来自不同进程的

class Test: 
    def __init__(self): 
     self.foo = [] 

    def append(self, x): 
     self.foo.append(x) 

    def get(self): 
     return self.foo 

def process_append_queue(append_queue, bar): 
    while True: 
     x = append_queue.get() 
     if x is None: 
      break 
     bar.append(x) 
    print("worker done") 

def main(): 
    import multiprocessing as mp 
    bar = Test() 
    append_queue = mp.Queue(10) 
    append_queue_process = mp.Process(target=process_append_queue, args=(append_queue, bar)) 
    append_queue_process.start() 

    for i in range(100): 
     append_queue.put(i) 
    append_queue.put(None) 
    append_queue_process.join() 

    print str(bar.get()) 

if __name__=="__main__": 
    main() 

当你在main()函数结束调用bar.get()为何仍返回一个空列表?我该如何做到这一点,以便子进程也适用于Test的同一个实例,而不是一个新实例?

所有答案赞赏!

回答

1

一般而言,进程具有不同的地址空间,因此一个进程中某个对象的突变对任何其他进程中的任何对象都没有影响。进程间通信需要告诉一个进程有关另一个进程所做的更改。

这可以明确地完成(使用诸如multiprocessing.Queue之类的东西),或者如果您为此目的使用由multiprocessing实现的设施,则隐式地完成。例如,在封面下进行了大量工作,以更改跨过程可见的multiprocessing.Queue

在具体的例子,最简单的方法是更换您的__init__功能,像这样:

def __init__(self): 
    import multiprocessing as mp 
    self.foo = mp.Manager().list() 

恰巧,一个mp.Manager实例支持list()方法创建流程识别列表对象(其实是一个代理对于一个列表对象,它将列表操作转发给维护单一副本“真实”列表的列表操作,列表对象并不真正在进程间共享,因为这是不可能的 - 但代理使它出现待分享)。

所以如果你做了这个改变,你的代码将显示你期望的结果 - 并且没有更简单的方法。

请注意,多处理的效果越好,所需的IPC(进程间通信)就越少,这与应用程序或编程语言无关。

2

通过酸洗它们并在管道上传递字符串来在进程之间复制对象。没有办法在进程之间为纯Python对象实现真正的“共享内存”。要准确实现这种同步,请参阅multiprocessing.Manager文档(https://docs.python.org/2/library/multiprocessing.html#managers),其中提供了有关常见Python容器类型的同步版本的示例。这些是“代理”容器,其中代理上的操作将跨过进程边界发送所有参数,进行酸洗,然后在父进程中执行。

相关问题