我有一个名为“Problem”的类,另外两个名为“Colony”和“Ant”。
“问题”的属性类型为“殖民地”,每个“殖民地”都有一个“蚂蚁”列表。
每个Ant被认为是在“问题”类中的方法中multiprocessing.JoinableQueue()
中运行的任务,当他们调用方法__call__
时,他们必须参考&修改“问题”类中的属性graph
,每个蚂蚁都必须访问该属性。
实现这一目标的最有效方法是什么?
我想过在构造函数方法中向每个ant传递一个图形的副本,然后在它们完成时,将所有子图形连接成一个图形。但我认为以某种方式直接由所有蚂蚁共享资源会更好,比如使用“信号量”风格设计。
有什么想法吗? 感谢
答案 0 :(得分:1)
如果分割数据并加入结果可以合理地完成,这几乎总是比让它们全部争夺共享数据更有效 - 而且更简单。
有些情况下没有合理的方法可以做到这一点(将结果重新加入非常复杂或非常慢)。但是,即使在这种情况下也可以有一个合理的替代方案:返回某种形式的“变异命令”。然后,父进程可以例如迭代输出队列并将每个结果应用于单个大数组。
即使这是不可行的,那么你需要分享。共享有两个部分:使数据本身可共享,并锁定它。
无论您的图表类型是什么,它可能都不具有固有的可共享性;它可能有内部指针等等。这意味着您需要根据multiprocessing.Array
或multiprocessing.sharedctypes
围绕Structure
等来构建某种表示形式,或者根据文件中的字节数构建每个进程可以mmap
,或使用您可能正在使用的NumPy等模块中可能存在的任何自定义多处理支持。然后,您的所有任务都可以改变Array
(或其他任何),最后,如果您需要额外的步骤将其转换回有用的图形对象,它应该非常快。
接下来,对于锁定,真正简单的事情是创建一个multiprocessing.Lock
,并在每个任务需要改变共享数据时抓住锁。在某些情况下,拥有多个锁可以更有效,保护共享数据的不同部分。并且在某些情况下,为每个突变获取锁定而不是为整个“交易”价值的序列抓取一次可能更有效(但当然它可能不是正确)。在不知道您的实际代码的情况下,无法对这些权衡做出判断;实际上,共享数据线程技术的很大一部分就是知道如何处理这些东西。 (并且很大一部分原因是无共享线程更容易,通常更高效的是你不需要需要来处理这些东西。)
与此同时,我不确定为什么你首先需要一个明确的JoinableQueue
。听起来你想要的一切都可以通过Pool
来完成。采取一个更简单但具体的例子:
a = [[0,1,2], [3,4,5], [6,7,8], [9,10,11]]
with multiprocessing.Pool() as pool:
b = pool.map(reversed, a, chunksize=1)
c = [list(i) for i in b]
这是一个非常愚蠢的例子,但它说明了每个任务在a
的一行上运行并返回一些东西,然后我可以用一些自定义的方式组合(通过调用list
每一个)得到我想要的结果。