我正在按预期使用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,000到100,000个元素。该值通常为3-5个元素。所以,酸洗肯定是个问题。如果不转移到共享内存中的某些内容,会建议哪些替代数据结构?
apply_async
具有类似的回调,保存for l in w
行,返回大致相同的结果。某些问题集的速度略高于map_async,而其他问题集的速度略差。使用托管dict和可连接队列要严重得多。
一些时间测试。这是使用2个核心。当我添加额外的核心时,我看到指数增加,所以我只能假设这种增加是由流程产生或酸洗返回数据引起的。
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
答案 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 ...
...
这应该很容易写和读。