【问题标题】:Multiprocessing.Manager() weird behavior with global variablesMultiprocessing.Manager() 全局变量的奇怪行为
【发布时间】:2016-08-24 07:39:10
【问题描述】:

当管理器对象是全局变量时,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]

【问题讨论】:

    标签: python multithreading global-variables python-multiprocessing


    【解决方案1】:

    虽然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 甚至都不是全局名称。它是函数参数之一的名称,因此其作用类似于函数局部变量名称。

    短期课程:停止思考名称,而是从对象的角度思考。名称从不跨进程共享。

    【讨论】:

      猜你喜欢
      • 2013-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-05
      • 2012-04-08
      • 2021-10-27
      • 2014-06-05
      • 2017-08-06
      相关资源
      最近更新 更多