栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

共享列表的多处理

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

共享列表的多处理

我认为这是由于实施经理的方式有些古怪。

如果创建两个Manager.list对象,然后将其中一个列表追加到另一个列表中,则您要追加的列表的类型将在父列表中更改:

>>> type(l)<class 'multiprocessing.managers.ListProxy'>>>> type(z)<class 'multiprocessing.managers.ListProxy'>>>> l.append(z)>>> type(l[0])<class 'list'>   # Not a ListProxy anymore

l[0]
并且
z
不是同一个对象,并且行为也不完全是您期望的结果:

>>> l[0].append("hi")>>> print(z)[]>>> z.append("hi again")>>> print(l[0])['hi again']

如您所见,更改嵌套列表对ListProxy对象没有任何影响,但是更改ListProxy对象确实会更改嵌套列表。该文档实际上明确指出了这一点:

注意

不能通过管理器传播对dict和list代理中的可变值或项的修改,因为代理无法知道何时修改其值或项。要修改此类项目,可以将修改后的对象重新分配给容器代理:

append
深入研究源代码,您可以看到,当您调用ListProxy时,附加调用实际上是通过IPC发送给管理器对象的,然后管理器调用了在共享列表上的附加。这意味着
append
需要腌制/未腌制的args
。在取消提取过程中,ListProxy对象被转换为常规的Python列表,该列表是ListProxy指向的内容(也称为其引用对象)的副本。文档中也对此进行了说明:

代理对象的一个​​重要功能是可拾取的,因此可以在进程之间传递。但是请注意,如果将代理发送给相应管理者的进程,则取消选择代理将自己生成引用对象。例如,这意味着一个共享对象可以包含第二个

因此,回到上面的示例,如果l
[0]是的副本

z
,为什么更新
z
也会更新
l[0]
?由于副本也已使用Proxy对象注册,因此,当您更改ListProxy(
z
在上面的示例中)时,它还会更新列表的所有已注册副本(
l[0]
在上面的示例中)。但是,副本对代理一无所知,因此当您更改副本时,代理不会更改。

因此,为了使您的示例正常工作,您

manager.list()
每次需要修改子列表时都需要创建一个新对象,并且仅直接更新该代理对象,而不是通过父列表的索引进行更新:

#!/usr/bin/pythonfrom multiprocessing import Process, Managerdef worker(x, i, *args):    sub_l = manager.list(x[i])    sub_l.append(i)    x[i] = sub_lif __name__ == '__main__':    manager = Manager()    x = manager.list([[]]*5)    print x    p = []    for i in range(5):        p.append(Process(target=worker, args=(x, i)))        p[i].start()    for i in range(5):        p[i].join()    print x

这是输出:

dan@dantop2:~$ ./multi_weirdness.py [[0], [1], [2], [3], [4]]


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/646956.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号