我对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
和dict1
已经被process1
修改了。
问题是,当我尝试更换list1
或dict1
时,它不起作用!
代码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
在任何其他进程中绑定到的对象产生影响。
因此,在第二个示例中,在工作进程中,名称list1
变为(重新)绑定到一个新的manager.list(range(100,104))
实例。这对主进程中名称list1
的绑定没有任何影响。工作进程也没有任何可能的方法来更改任何其他进程中任何名称的绑定——如果发生这种情况,那将是一场噩梦。
不过,您可以更改共享对象的值。但你似乎已经知道了。例如,进行
list1[:] = range(100,104)
相反,不更改绑定,而是替换共享Manager.list
实例的整个内容(因此主进程也会看到新的列表内容,不是因为名称相同,而是因为两个名称都绑定到同一对象)。
顺便说一句,请注意,在process1
函数中,list1
甚至不是全局名称。它是函数的一个参数的名称,因此其作用类似于函数的局部变量名。
短期课程:停止思考名字,而是从物体的角度思考。名称从不在进程之间共享。