Multiprocessing.Manager()使用全局变量

时间:2016-04-29 08:27:27

标签: python multithreading global-variables python-multiprocessing

我遇到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}

好的,这意味着̀list1修改了全局变量dict1process1

问题在于,当我尝试替换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]

1 个答案:

答案 0 :(得分:0)

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

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

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

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

list1[:] = range(100,104)

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

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

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