我已经在multiprocessing.Manager.dict
对象中创建了一个嵌套字典。当我将字典方法应用到嵌套字典中时,像update
、clear
等字典方法不起作用。这就是一个例子:
from multiprocessing import Manager, Process
def worker(shared_object):
print(f'Before defining the nested dictionary: {shared_object}')
shared_object['nested'] = {
'first_key': 'first_value'
}
print(f'After defining the nested dictionary: {shared_object}')
shared_object['nested'].update(
{
'second_key': 'second_value'
}
)
print(f'After updating the nested dictionary: {shared_object}')
if __name__ == '__main__':
with Manager() as manager:
shared_dict = manager.dict()
worker_one = Process(target=worker, args=(shared_dict,))
worker_one.start()
worker_one.join()
这就是结果:
Before defining the nested dictionary: {}
After defining the nested dictionary: {'nested': {'first_key': 'first_value'}}
After updating the nested dictionary: {'nested': {'first_key': 'first_value'}}
我能做什么?
发布于 2022-08-19 14:35:48
共享字典的用法与以下内容相同,可以重写如下:
temp = shared_object['nested']
temp.update({'second_key': 'second_value'})
当您从共享字典请求nested
键的值时,它将存储在当前进程的内存空间中。这意味着,您对此字典所做的任何更改都不会反映在存储在管理器中的共享字典中,因为管理器无法知道在检索字典的子集后对字典做了什么。因此,您需要做的是通知经理您已经对嵌套字典进行了更改。有两种方法可以做到这一点:
使用更新的值显式调用manager对象。
在这里,在对嵌套字典进行任何更改之后,这可能是最简单的(也是性能上最快的)修复,显式地将键的值设置为修改过的字典:
temp = shared_object['nested']
temp.update({'second_key': 'second_value'})
shared_object['nested'] = temp
这样做将让经理知道托管对象中发生了更改。
为嵌套字典创建另一个托管对象(手动vs自动)
实现这一点的另一种方法是为嵌套字典创建托管对象并将其存储起来。但是,请记住,如果对象的嵌套级别非常深,这会很快变得不方便。这是因为对于每个嵌套字典,您需要创建另一个托管对象。此外,如果您创建的子进程是守护进程(在使用multiprocessing.Pool
时是默认的),并且它们需要在共享字典中添加自己的嵌套对象,则这将无法工作。这是因为要创建一个托管对象,您需要启动一个管理器进程,而守护进程不能生成它们自己的进程。
但是,如果让共享字典负责,如果有人试图在共享字典中存储嵌套字典,那么这两个问题都可以很快得到解决。如果有人试图在共享字典中存储嵌套字典,那么这两个问题都可以很快得到解决。下面给出了一个示例,说明如何做到这一点(它适用于列表和字典):
from multiprocessing.managers import SyncManager, MakeProxyType, ListProxy, State
from multiprocessing import Process, Lock
from collections import UserDict
from collections import UserList
class ManagerList(UserList):
def __check_state(self):
global manager
global lock
# Managers are not thread-safe, protect starting one from within another with a lock
with lock:
if manager._state.value != State.STARTED:
manager.start(initializer=init)
def __setitem__(self, key, value):
global manager
self.__check_state()
if isinstance(value, list):
value = manager.list(value)
elif isinstance(value, dict):
value = manager.dict(value)
return super().__setitem__(key, value)
class ManagerDict(UserDict):
def __check_state(self):
global manager
global lock
# Managers are not thread-safe, protect starting one from within another with a lock
with lock:
if manager._state.value != State.STARTED:
manager.start(initializer=init)
def __setitem__(self, key, value):
global manager
self.__check_state()
if isinstance(value, list):
value = manager.list(value)
elif isinstance(value, dict):
value = manager.dict(value)
return super().__setitem__(key, value)
ManagerDictProxy = MakeProxyType('DictProxy', (
'__contains__', '__delitem__', '__getitem__', '__iter__', '__len__',
'__setitem__', 'clear', 'copy', 'get', 'items',
'keys', 'pop', 'popitem', 'setdefault', 'update', 'values'
))
ManagerDictProxy._method_to_typeid_ = {
'__iter__': 'Iterator',
}
SyncManager.register('list', ManagerList, ListProxy)
SyncManager.register('dict', ManagerDict, ManagerDictProxy)
def init():
global manager
global lock
lock = Lock()
manager = SyncManager()
def worker(shared_object):
print(f'Before defining the nested dictionary: {shared_object}')
shared_object['nested'] = {
'first_key': 'first_value',
}
print(f'After defining the nested dictionary: {shared_object["nested"]}')
shared_object['nested'].update(
{
'second_key': 'second_value'
}
)
print(f'After updating the nested dictionary: {shared_object["nested"]}')
if __name__ == "__main__":
manager = SyncManager()
manager.start(initializer=init)
d = manager.dict() # It works with manager.list() too
p = Process(target=worker, args=(d, ))
p.start()
p.join()
这使用__setitem__
dunder方法来检查分配给字典的值是另一个列表还是一个字典,如果是,它会为它们创建一个托管对象并将其存储起来。现在对这些嵌套字典/列表所做的任何更改也将反映在原始字典中。这适用于任意数量的嵌套级别。
但是,请记住,只有当数据类型为list
或dict
(或它们的子类)时,才会创建托管对象。此外,它还为每个嵌套级别创建了一个管理流程。因此,使用第一种方法总是比使用这个方法更快,尽管这个方法更方便。
输出
Before defining the nested dictionary: {}
After defining the nested dictionary: {'first_key': 'first_value'}
After updating the nested dictionary: {'first_key': 'first_value', 'second_key': 'second_value'}
https://stackoverflow.com/questions/73409151
复制相似问题