multiprocessing
模块状态的Python文档:
共享对象可以嵌套。例如,共享容器对象(例如共享列表)可以包含其他共享对象,这些对象都将由SyncManager管理和同步。
这确实适用于list
和dict
。但是,如果我尝试在共享的Queue
中创建共享的dict
,则会收到错误消息:
>>> from multiprocessing import Manager
>>> m = Manager()
>>> d = m.dict()
>>> d['a'] = m.list()
>>> d['b'] = m.dict()
>>> d['c'] = m.Queue()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 2, in __setitem__
File "/usr/lib/python3.6/multiprocessing/managers.py", line 772, in _callmethod
raise convert_to_error(kind, result)
multiprocessing.managers.RemoteError:
---------------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/lib/python3.6/multiprocessing/managers.py", line 228, in serve_client
request = recv()
File "/usr/lib/python3.6/multiprocessing/connection.py", line 251, in recv
return _ForkingPickler.loads(buf.getbuffer())
File "/usr/lib/python3.6/multiprocessing/managers.py", line 881, in RebuildProxy
return func(token, serializer, incref=incref, **kwds)
TypeError: AutoProxy() got an unexpected keyword argument 'manager_owned'
---------------------------------------------------------------------------
似乎https://hg.python.org/cpython/rev/39e7307f9aee是引入嵌套共享对象的变更集。
答案 0 :(得分:1)
该错误是由AutoProxy
当前未处理所有BaseProxy
自变量引起的。有一个pull request尚未合并。您要么需要猴子AutoProxy
补丁,要么调查multiprocessing.managers.py
并将补丁here中的更改直接应用于源代码。
修复补丁中的两行以防止服务器进程中的内存泄漏非常重要。 manager_owned
标志用于通知BaseProxy
代码,何时跳过管理者拥有的代理的引用增量(通过嵌套)。
答案 1 :(得分:1)
如果不想修补基础python库,则可以使用以下代码在自己的代码中应用此修补程序。
我已经从@Darkonaut的pull request参考中复制了更改,并进行了软件包名称的修改,因此它可以在原始软件包之外使用。它将放置在使用multiprocessing.managers
的任何模块的模块级别。
请注意,@ Darkonaut的答案中的solution I referenced注释在我自己的测试中产生了段错误,但是此解决方案却没有。
import multiprocessing.managers
def AutoProxy(token, serializer, manager=None, authkey=None,
exposed=None, incref=True, manager_owned=False):
'''
Return an auto-proxy for `token`
'''
_Client = multiprocessing.managers.listener_client[serializer][1]
if exposed is None:
conn = _Client(token.address, authkey=authkey)
try:
exposed = dispatch(conn, None, 'get_methods', (token,))
finally:
conn.close()
if authkey is None and manager is not None:
authkey = manager._authkey
if authkey is None:
authkey = multiprocessing.process.current_process().authkey
ProxyType = multiprocessing.managers.MakeProxyType('AutoProxy[%s]' % token.typeid, exposed)
proxy = ProxyType(token, serializer, manager=manager, authkey=authkey,
incref=incref, manager_owned=manager_owned)
proxy._isauto = True
return proxy
multiprocessing.managers.AutoProxy = AutoProxy