Python:使用多维multiprocessing.manager.list()

Python: Using a multidimensional multiprocessing.manager.list()

这可能不是它的预期用途,但我想知道如何使用多维 manager.list()。我可以很好地创建,像这样:

from multiprocessing import manager

test = manager.list(manager.list())

然而,每当我尝试访问测试列表的第一个元素时,它 returns 元素的值而不是它的代理对象

test[0]  # returns [] and not the proxy, since I think python is running __getitem__.

我有没有办法解决这个问题并以这种方式使用 manager.list()?

multiprocessing documentation对此有说明:

Note

Modifications to mutable values or items in dict and list proxies will not be propagated through the manager, because the proxy has no way of knowing when its values or items are modified. To modify such an item, you can re-assign the modified object to the container proxy:

# create a list proxy and append a mutable object (a dictionary) 
lproxy = manager.list() 
lproxy.append({})
# now mutate the dictionary 
d = lproxy[0]
d['a'] = 1 
d['b'] = 2
# at this point, the changes to d are not yet synced, but by
# reassigning the dictionary, the proxy is notified of the change 
lproxy[0] = d

因此,使用多维列表的唯一方法是将您对列表的第二维所做的任何更改重新分配回顶级列表,而不是:

test[0][0] = 1

你做到了:

tmp = test[0]
tmp[0] = 1
test[0] = tmp

这不是最令人愉快的做事方式,但您可能可以编写一些辅助函数以使其更容易接受。

编辑:

当您将一个 ListProxy 附加到另一个 ListProxy 时,您得到一个普通列表的原因似乎是酸洗代理的工作方式。 BaseProxy.__reduce__ 创建一个 RebuildProxy 对象,它实际上是用来解开 Proxy 的。 RebuildProxy 看起来像这样:

def RebuildProxy(func, token, serializer, kwds):
    '''
    Function used for unpickling proxy objects.

    If possible the shared object is returned, or otherwise a proxy for it.
    '''
    server = getattr(process.current_process(), '_manager_server', None)

    if server and server.address == token.address:
        return server.id_to_obj[token.id][0]
    else:
        incref = (
            kwds.pop('incref', True) and
            not getattr(process.current_process(), '_inheriting', False)
            )
        return func(token, serializer, incref=incref, **kwds)

正如文档字符串所说,如果 unpickling 发生在管理器服务器内部,则会创建实际的共享对象,而不是 Proxy。这可能是一个错误,there is actually one filed 已经反对这种行为。