在python多处理模块中使用Manager()共享数据



我试图在使用multiprocessing模块(python 2.7, Linux)时共享数据,当使用稍微不同的代码时,我得到了不同的结果:

import os
import time
from multiprocessing import Process, Manager
def editDict(d):
    d[1] = 10
    d[2] = 20
    d[3] = 30

pnum = 3
m = Manager()

版本1:

mlist = m.list()
for i in xrange(pnum):
    mdict = m.dict()
    mlist.append(mdict)
    p = Process(target=editDict,args=(mdict,))
    p.start()
time.sleep(2)
print 'after process finished', mlist
由此产生

:

过程完成后({2:1:10日20日3:30},{3:2:1:10日20日30},{3:2:1:10日20日30}]

版本2:

mlist = m.list([m.dict() for i in xrange(pnum)]) # main difference to 1st version
for i in xrange(pnum):
    p = Process(target=editDict,args=(mlist[i],))
    p.start()
time.sleep(2)
print 'after process finished', mlist
由此产生

:

进程结束后[{},{},{}]

我不明白为什么结果如此不同。

这是因为您第二次通过列表索引访问变量,而第一次传递实际变量。如多处理文档中所述:

对字典和列表代理中的可变值或项的修改将不会通过管理器传播,因为代理无法知道它的值或项何时被修改。

这意味着,为了跟踪容器(字典或列表)中更改的项,您必须在每次编辑后重新分配它们。考虑下面的修改(为了解释,我不认为这是干净的代码):

def editDict(d, l, i):
    d[1] = 10
    d[2] = 20
    d[3] = 30
    l[i] = d
mlist = m.list([m.dict() for i in xrange(pnum)])
for i in xrange(pnum):
    p = Process(target=editDict,args=(mlist[i], mlist, i,))
    p.start()

如果您现在打印mlist,您将看到它与您第一次尝试的输出相同。重新赋值将允许容器代理再次跟踪更新的项。

在这种情况下,您的主要问题是您在list代理中有一个dict(代理):对所包含的容器的更新不会被管理器注意到,因此没有您期望的更改。请注意,在第二个示例中,字典本身将被更新,但由于管理器没有同步,因此您无法看到它。

最新更新