我想更新dict
中的dict
,外部版本通过multiprocessing.Manager()
进行实例化:
import multiprocessing
def worker(key, container):
# this one is not applied
container['a'][key] = key
# this one is
container[key] = 3
if __name__ == "__main__":
multiprocessing.freeze_support()
c = multiprocessing.Manager().dict()
c['a'] = {}
p1 = multiprocessing.Process(target=worker, args=('x',c,))
p2 = multiprocessing.Process(target=worker, args=('y',c,))
p1.start()
p2.start()
p1.join()
p2.join()
print(c.copy())
此代码的输出是
{'y': 3, 'a': {}, 'x': 3}
我希望得到
{'y': 3, 'a': {'x': 'x', 'y': 'y'}, 'x': 3}
dict
的第一级可在worker
中寻址,但嵌套dict
上的操作会被静默丢弃。为什么?
我最初认为这是因为浅拷贝,但使用copy.deepcopy()
答案 0 :(得分:1)
使用子进程实现Manager
,该子进程保留dict
对象的本地版本,并提供模仿对象行为的代理函数,而不Manager
。
当您调用container['a']
时,使用代理函数返回与'a'
键关联的值的本地副本。因此,如果您在其中一个子流程中修改此副本,则更改仅为本地更改。如果您想要进行全局变更,可以:
修改本地副本并使用您提议的set
,即 container['a'] = new_dict
的代理进行同步。不方便的是它不是原子的,因此你有一些并发问题,好像p1
和p2
得到字典,都得到{}
,他们提交的更新将是{{1只考虑其他更新而不考虑其他更新,最后只会注册第二个。
更好的方法是使用嵌套的{key: key}
:
Manager.dict
答案 1 :(得分:1)
您应该将Manager的实例传递给子流程,例如
import multiprocessing
def worker(key, container, manager):
container[key] = manager.dict() # create a dict using current manager
container[key][1] = 3
container[key][2] = manager.dict() # # create a dict using current manager
container[key][2]['hh'] = 'test'
if __name__ == "__main__":
with multiprocessing.Manager() as m:
c = m.dict()
c['a'] = 1
p1 = multiprocessing.Process(target=worker, args=('x',c,m))
p2 = multiprocessing.Process(target=worker, args=('y',c,m))
p1.start()
p2.start()
p1.join()
p2.join()
print(c['a'])
print(c['x'][1])
print(c['x'][2]['hh'])
print(c['y'][1])
print(c['y'][2]['hh'])
输出为
> $ python3.7 ddd.py
1
3
test
3
test
答案 2 :(得分:0)
我认为这是a bug。
我找到了一种绕过这个问题的深奥方法,我不确定它有多强大。欢迎任何反馈。
import multiprocessing
def worker(key, container):
add = {key: key}
container['a'] = dict(container['a'], **add)
container[key] = 3
if __name__ == "__main__":
multiprocessing.freeze_support()
c = multiprocessing.Manager().dict()
c['a'] = {}
p1 = multiprocessing.Process(target=worker, args=('x',c,))
p2 = multiprocessing.Process(target=worker, args=('y',c,))
p1.start()
p2.start()
p1.join()
p2.join()
print(c.copy())
此输出
{'y': 3, 'a': {'y': 'y', 'x': 'x'}, 'x': 3}