繁体   English   中英

Multiprocessing.Manager()具有全局变量的奇怪行为

[英]Multiprocessing.Manager() weird behavior with global variables

我有一个multiprocessing.Manager类的问题,当管理器对象是全局变量时,它有一个非常奇怪的行为。

代码1:

import multiprocessing
from multiprocessing import Manager

manager = Manager()

list1 = manager.list(range(4))
dict1 = manager.dict({"d":1,"f":2})

def process1(list1,dict1):
    print "process1"
    dict1["3"] = 123
    list1.append(10)

def run():
    print "start"
    global list1
    global dict1

    print "list1",list1
    print "dict1",dict1

if __name__ == '__main__':
    print "start"
    j = multiprocessing.Process(target=process1, args=(list1,dict1))
    j.start()
    j.join()
    run()

输出1:

start
process1
start
list1 [0, 1, 2, 3, 10]
dict1 {'3': 123, 'd': 1, 'f': 2}

好的,这意味着全局变量̀list1dict1已被process1修改。

问题是,当我尝试替换list1dict1它不起作用!

代码2:

import multiprocessing
from multiprocessing import Manager

manager = Manager()

list1 = manager.list(range(4))
dict1 = manager.dict({"d":1,"f":2})

def process1(list1,dict1):
    print "process1"
    dict1["3"] = 123
    list1 = manager.list(range(100,104))

def run():
    print "start"
    global list1
    global dict1

    print "list1",list1
    print "dict1",dict1

if __name__ == '__main__':
    print "start"
    j = multiprocessing.Process(target=process1, args=(list1,dict1))
    j.start()
    j.join()
    run()

输出2:

start
process1
start
list1 [0, 1, 2, 3]
dict1 {'3': 123, 'd': 1, 'f': 2}

知道为什么它返回初始列表[0, 1, 2, 3]而不是[100, 101, 102, 103]

虽然Manager.list对象是跨进程共享的,但绑定到该对象的名称根本不会共享 - 即使您在所有进程中使用相同的名称也是如此。 global意味着在运行模块的进程中,整个模块都会看到相同的绑定(除非在某些本地范围内被覆盖); 它并不神奇地意味着更多只是因为multiprocessing被导入;-)

具体来说,名称list1中的主要过程无关的名称list1中的工作进程。 它们唯一的关系是两个名称最初都绑定到Manager.list的单个共享实例。 这通常是你想要的。 在任一进程中将名称list1重新绑定到某个其他对象,对名称list1在任何其他进程中绑定的对象没有影响。

因此,在第二个示例中,在worker进程中,名称list1变为(重新)绑定到新的manager.list(range(100,104))实例。 这对主进程中名称list1的绑定没有任何影响。 工作进程也没有任何可能的方法来改变任何其他进程中任何名称的绑定 - 如果可能发生这将是一场噩梦。

但是,您可以更改共享对象 但你似乎已经知道了。 例如,做

list1[:] = range(100,104)

而不是更改任何绑定,但替换共享Manager.list实例的整个内容(因此主进程也将看到新的列表内容,因为名称是相同的,但因为两个名称都绑定到同一个对象 )。

请注意,在您的process1函数中,无论如何, list1甚至都不是全局名称。 它是函数参数之一的名称,因此就像函数本地变量名一样。

短期课程:不要再考虑名称,而是考虑对象。 名称永远不会在进程间共享。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM