更新来自不同进程的相同实例变量
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(进程间通信)越少,多处理效果越好,无论应用程序或编程语言如何,这几乎都是事实。
这是一个简单的 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(进程间通信)越少,多处理效果越好,无论应用程序或编程语言如何,这几乎都是事实。