使用多处理创建一个集合

时间:2018-02-17 19:36:00

标签: python python-multiprocessing

我有很多项目和一些辅助数据。对于列表中的每个项目和数据中的元素,我计算一些东西,并将所有内容添加到输出集中(可能有许多重复项)。在代码中:

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()的那些更快?另外,我怎样才能找回工会进行工会计算的集合?

1 个答案:

答案 0 :(得分:1)

一件小事:initiargs需要一个元组。

如果您想在将它们缩减为set之前避免创建所有结果,则可以使用Pool.imap_unordered()一些块大小。这将产生每个工人可用时的块大小结果。

如果要将process_item更改为直接接受块,则必须手动执行。 toolz.partition_all可用于对初始数据集进行分区。

最后,托管数据结构必然会有更高的同步开销。我会尽可能地避免它们。

imap_unordered一起去看看是否足够好;如果没有,那么分区;如果你不能帮助总共重复几次,请使用托管字典。