我在尝试实施新的defaultdict
代理对象时遇到了一些麻烦。 documentation有点恐慌,所以我不确定如何正确地解决这个问题。
我想将defaultdict
添加到Manager
实例中可用的类型列表中。您无法在库存Manager.register
上使用multiprocessing.Manager
方法,因此我已经从multiprocessing.mangers.BaseManager
class Manager(BaseManager):
pass
然后我创建了multiprocessing.managers.BaseProxy
的子类来容纳defaultdict
(我最初尝试使用另一个存根,它将子类化defaultdict
和BaseProxy
但是没有#39}似乎工作。这是我现在拥有的:
class ProxyDefaultDict(BaseProxy):
def __init__(self, default_factory=None, *args, **kwargs):
self.__data = defaultdict(default_factory)
super().__init__(*args, **kwargs)
def _callmethod(self, methodname, args=(), kwds={}):
return getattr(self.__data, methodname)(*args, **kwds)
def _getvalue(self):
return self.__data.copy()
def __repr__(self):
return self.__data.__repr__()
def __str__(self):
return self.__data.__str__()
Manager.register('defaultdict', ProxyDefaultDict)
最终目标是拥有一个共享字典,可以跨进程和线程安全地共享密钥锁。以下是我将如何对其进行初始化的示例:
if __name__ == '__main__':
m = Manager()
d = m.defaultdict(m.Lock)
with d['named_lock']:
print('holding the lock')
但是,我遇到了一些问题:
BaseManager的子类似乎只能通过上下文管理器with Manager() as m
来初始化。在这种情况下我会使用m = Manager()
- 正如multiprocessing.Manager
允许的那样。不是世界末日,而是更好奇为什么会出现这种情况,如果这是一个我不正确做错的迹象。
对multiprocessing.managers.BaseManager
进行子类化也可以解除multiprocessing.Manager
的默认注册值。在这种情况下,我需要为我的经理重新注册ProxyLock(我也不确定预期的方法)。直接继承multiprocessing.Manager
是否安全。
最后,我的ProxyDefaultDict
似乎不允许我干净地覆盖其__init__
。而且我很遗憾在子类化时不调用BaseProxy.__init__
。问题是BaseProxy也接受位置参数。我想这样做的方法是将default_factory
参数仅作为一个键控参数,但这会将预期的接口更改为defaultdict
,并让我假设我在这里再次做错了。像Manager.Lock
这样的其他类型似乎能够接受位置参数。
感谢您的帮助。
答案 0 :(得分:5)
查看源代码之后,对它进行一点修改就可以让我获得一个没有问题的defaultdict类型代理(基于如何创建内置的DictProxy)。
seeds
就个人而言,通过使用已经提供的工具,我觉得很方便,甚至不用担心如何自己进行子类化。
但是,我不认为这将允许您创建您正在寻找的默认锁定方案。多处理锁被设计为仅被继承,并且通常不能对Lock进行pickle,这是通过代理传输的数据类型的要求。示例:
from collections import defaultdict
from multiprocessing.managers import MakeProxyType, SyncManager
DefaultDictProxy = MakeProxyType("DefaultDictProxy", [
'__contains__', '__delitem__', '__getitem__', '__len__',
'__setitem__', 'clear', 'copy', 'default_factory', 'fromkeys',
'get', 'items', 'keys', 'pop', 'popitem', 'setdefault',
'update', 'values'])
SyncManager.register("defaultdict", defaultdict, DefaultDictProxy)
# Can also create your own Manager here, just using built in for simplicity
if __name__ == '__main__':
with SyncManager() as sm:
dd = sm.defaultdict(list)
print(dd['a'])
# []
会引发运行时错误:
from multiprocessing import Lock
m = SyncManager()
m.start()
d = m.defaultdict(Lock)
print(d['named_lock'])
m.shutdown()