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

Updating the same instance variables from different processes

这是一个简单的 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()

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

感谢所有回答!

通过对对象进行酸洗并通过管道传递字符串,在进程之间复制对象。对于进程之间的纯 Python 对象,无法实现真正​​的 "shared memory"。要准确实现这种类型的同步,请查看 multiprocessing.Manager 文档 (https://docs.python.org/2/library/multiprocessing.html#managers),其中提供了有关常见 Python 容器类型的同步版本的示例。这些是 "proxied" 容器,代理上的操作在其中跨进程边界发送所有参数,pickle,然后在父进程中执行。

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

这可以明确地完成(使用 multiprocessing.Queue 之类的东西),或者如果您为此目的使用由 multiprocessing 实现的工具,则可以隐式地完成。例如,大量工作是在幕后完成的,以对 multiprocessing.Queue 跨进程可见的内容进行更改。

在您的特定示例中,最简单的方法是像这样替换您的 __init__ 函数:

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

碰巧 mp.Manager 实例支持 list() 方法创建进程感知列表对象(实际上是列表对象的代理,它将列表操作转发到底层- 涵盖维护 "the real" 列表的单个副本的服务器进程 - 列表对象并不是真正跨进程共享,因为那是不可能的 - 但代理使它 看起来 是共享)。

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

请注意,您需要的 IPC(进程间通信)越少,多处理效果越好,无论应用程序或编程语言如何,这几乎都是事实。