![](/img/trans.png)
[英]Python multiprocessing.Manager and os.fork producing strange behavior
[英]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}
好的,这意味着全局变量̀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
在任何其他进程中绑定的对象没有影响。
因此,在第二个示例中,在worker进程中,名称list1
变为(重新)绑定到新的manager.list(range(100,104))
实例。 这对主进程中名称list1
的绑定没有任何影响。 工作进程也没有任何可能的方法来改变任何其他进程中任何名称的绑定 - 如果可能发生这将是一场噩梦。
但是,您可以更改共享对象值 。 但你似乎已经知道了。 例如,做
list1[:] = range(100,104)
而不是更改任何绑定,但替换共享Manager.list
实例的整个内容(因此主进程也将看到新的列表内容,因为名称是相同的,但因为两个名称都绑定到同一个对象 )。
请注意,在您的process1
函数中,无论如何, list1
甚至都不是全局名称。 它是函数参数之一的名称,因此就像函数本地变量名一样。
短期课程:不要再考虑名称,而是考虑对象。 名称永远不会在进程间共享。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.