我有很多项目和一些辅助数据。对于列表中的每个项目和数据中的元素,我计算一些东西,并将所有内容添加到输出集中(可能有许多重复项)。在代码中:
def process_list(myList, data):
ret = set()
for item in myList:
for foo in data:
thing = compute(item, foo)
ret.add(thing)
return ret
if __name__ == "__main__":
data = create_data()
myList = create_list()
what_I_Want = process_list(myList, data)
因为myList很大而且compute(item,foo)代价很高,所以我需要使用多处理。现在这就是我所拥有的:
from multiprocessing import Pool
initialize_worker(bar):
global data
data = bar
def process_item(item):
ret = set()
for foo in data:
thing = compute(item, foo)
ret.add(thing)
return ret
if __name__ == "__main__":
data = create_data()
myList = create_list()
p = Pool(nb_proc, initializer = initialize_worker, initiargs = (data))
ret = p.map(process_item, myList)
what_I_Want = set().union(*ret)
我不喜欢的是ret可能很大。我在考虑3个选项:
1)将myList切换成块,将它们传递给工作人员,工作人员将在每个块上使用process_list(因此在该步骤中将删除一些重复项),然后将所有获取的集合联合以删除最后一个重复项。
问题:这样做有一种优雅的方式吗?我们可以指定Pool.map它应该将块传递给工作者而不是块中的每个项目吗?我知道我可以自己砍掉这份名单,但这真是太可怕了。
2)在所有进程之间建立共享集。
问题:为什么multiprocessing.manager没有set()功能? (我知道它有dict(),但仍然..)如果我使用manager.dict(),那么进程和管理器之间的通信是否会大大减慢这一点?
3)拥有共享的multiprocessing.Queue()。每个工作人员将计算的内容放入队列中。另一个工作者进行并集直到找到一些stopItem(我们将其放入p.map之后的队列中)
问题:这是一个愚蠢的想法吗?进程和多处理之间的通信是否比使用manager.dict()的那些更快?另外,我怎样才能找回工会进行工会计算的集合?
答案 0 :(得分:1)
一件小事:initiargs
需要一个元组。
如果您想在将它们缩减为set
之前避免创建所有结果,则可以使用Pool.imap_unordered()
一些块大小。这将产生每个工人可用时的块大小结果。
如果要将process_item
更改为直接接受块,则必须手动执行。 toolz.partition_all
可用于对初始数据集进行分区。
最后,托管数据结构必然会有更高的同步开销。我会尽可能地避免它们。
与imap_unordered
一起去看看是否足够好;如果没有,那么分区;如果你不能帮助总共重复几次,请使用托管字典。