从不同进程更新相同的实例变量

时间:2016-05-16 03:06:09

标签: python multiprocessing shared-memory

这是一个简单的secinaro:

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()

当您在bar.get()函数末尾调用main()时,为什么它仍会返回空列表?我怎样才能使子进程也使用Test的同一个实例而不是新实例?

所有答案都赞赏!

2 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:2)

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

可以明确地(使用诸如multiprocessing.Queue之类的内容)完成,或者如果您为此目的使用multiprocessing实现的工具,则可以隐式执行。例如,在封面下完成了大量工作,以便对跨进程的multiprocessing.Queue进行更改。

您的具体示例中最简单的方法是替换__init__函数,如下所示:

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

恰好,mp.Manager实例支持list()方法,该方法创建了一个进程感知列表对象(实际上是列表对象的代理,它将列表操作转发给封面维护单个副本&#34;真实&#34;列表的服务器进程 - 列表对象并非真正在进程间共享,因为这是不可能的 - 但代理使出现< / em>待共享)。

因此,如果您进行了更改,您的代码将显示您期望的结果 - 并且没有更简单的方法。

请注意,多处理在您需要的IPC(进程间通信)较少的情况下工作得更好,而且无论应用程序或编程语言如何,这都是正确的。