python map_async,来自哪里的开销?

时间:2013-05-02 18:06:49

标签: python map multiprocessing

我正在按预期使用map_async - 使用以下方法在多个处理核心上映射可迭代:

cores = mp.cpu_count()
pool = mp.Pool()

r = pool.map_async(func, offsets,callback=mycallback)
r.wait()

func返回一个字典,因此回调'合并'使用的字符串:

ddict = defaultdict(set)
def mycallback(w):
    for l in w:
        for key, value in l.items():
            for v in value:
                ddict[key].add(v)  

Offsets是我用1,000 - 50,000个元素测试过的迭代。

如果我删除r.wait(),则无法返回map_async来电的所有输出。

使用r.wait(),我发现处理时间都不如串行实现,并且不能扩展,即并行实现会按指数增加,而串行版本会线性增加。

我知道func足够昂贵,因为串行和并行它会占用我的处理内核。

我在哪里使用map_async引入了开销?它不在回调函数中,因为删除和替换result.append不会影响时间。

编辑评论:

  1. 我正在移动大量的词组,大约1,000到100,000个元素。该值通常为3-5个元素。所以,酸洗肯定是个问题。如果不转移到共享内存中的某些内容,会建议哪些替代数据结构?

  2. apply_async具有类似的回调,保存for l in w行,返回大致相同的结果。某些问题集的速度略高于map_async,而其他问题集的速度略差。使用托管dict和可连接队列要严重得多。

  3. 一些时间测试。这是使用2个核心。当我添加额外的核心时,我看到指数增加,所以我只能假设这种增加是由流程产生或酸洗返回数据引起的。

  4. func获取数据点并查找邻居。对于所有情况,它都是一个相同的函数,除了需要传递偏移量告诉并行代码搜索哪些数据点。这基本上是一个KDTree搜索功能。

    同质分布

    1,000个数据点:序列号0.098659992218 | apply_async 0.120759010315 | map_async 0.080078125

    10,000个数据点< ======只有并行改进|序列号0.507845163345 | apply_async 0.446543931961 | map_async 0.477811098099

    随机分发

    10,000个数据点:Serial 0.584854841232 | apply_async 1.03224301338 | map_async 0.948460817337

    50,000个数据点:Serial 3.66075992584 | apply_async 4.95467185974 | map_async 5.37306404114

1 个答案:

答案 0 :(得分:3)

您可以更改func()以返回集的字典而不是列表的字典吗?然后你的回调函数可以像这样重写:

def mycallback(w):
    for l in w:
        for key, value in l.items():
            ddict[key].update(value)

这应该有助于串行和并行处理时间。

不幸的是,我认为@Dougal在线程之间传递时对所有数据进行pickle / unpickling是正确的。将二进制数据写入磁盘并再次读取它可能会更快,而不是因为酸洗的开销而将其传递到内存中。您可以使用以下格式:

key value1 value2 value3 ...
key2 valueA valueB valueC ...
...

这应该很容易写和读。