在进程之间修改共享的dict对象并不起作用

时间:2014-09-24 14:22:28

标签: python multiprocessing

我想我已经在这里发现了一个类似的问题,但没有找到一个我能够轻易理解的好解释。我也尝试阅读python doc,但也没有找到详细的解释。

现在这里是代码:

from multiprocessing import Process, Manager

def f(d):
    d[1] = [[1]] 
    if 2 in d.keys():
       d[2].append([2])
    else:
       d[2] = [[2]]
    d[3] = [[3]]

if __name__ == '__main__':

    with Manager() as manager:
        d = manager.dict()

        p1 = Process(target=f, args=(d,))
        p2 = Process(target=f, args=(d,))
        p1.start()
        p2.start
        p1.join()
        p2.join

        print(d)

我有两个进程正在运行并从Manager进程共享一个dict对象。我可以向dict对象添加新的键值对,但如果键已存在则无法修改值。

为什么会这样?如果我们想要修改使用这样的共享对象会出现什么问题?

1 个答案:

答案 0 :(得分:2)

首先,你没有开始第二个过程。

p2.start   # <--- no `()`
p2.join    # <--- no `()`

其次,根据multiprocessing.managers.SyncManager documentation NOTE

  

注意:修改dict和列表代理中的可变值或项目   不能通过管理器传播,因为代理无法通过   知道何时修改其值或项目。 要修改此类项目,   您可以将修改后的对象重新分配给容器代理。

所以,你的程序应该是这样的:

from multiprocessing import Process, Manager

def f(d):
    d[1] = [[1]] 
    if 2 in d:  # NOTE: You don't need to use `keys()`. `dict` support `in` operator.
       d[2] = d[2] + [[2]]
    else:
       d[2] = [[2]]
    d[3] = [[3]]

if __name__ == '__main__':

    with Manager() as manager:
        d = manager.dict()

        p1 = Process(target=f, args=(d,))
        p2 = Process(target=f, args=(d,))
        p1.start()
        p2.start()
        p1.join()
        p2.join()

        print(d)

但是,还有另一个问题。以下语句涉及多次读取,写入共享对象;这不是原子的;因此,无法保证上述程序每次都能产生相同的结果。

if 2 in d:
   d[2] = d[2] + [[2]]
else:
   d[2] = [[2]]

您需要使用锁来确保共享对象只能由一个进程访问。