我有一个非常大的字符串列表(最初来自文本文件),我需要使用python进行处理。最终我试图采用map-reduce风格的并行处理。
我编写了一个“mapper”函数并将其提供给multiprocessing.Pool.map()
,但它与使用完整数据集调用mapper函数所花费的时间相同。我一定是做错了。
我尝试了多种方法,都有类似的结果。
def initial_map(lines):
results = []
for line in lines:
processed = # process line (O^(1) operation)
results.append(processed)
return results
def chunks(l, n):
for i in xrange(0, len(l), n):
yield l[i:i+n]
if __name__ == "__main__":
lines = list(open("../../log.txt", 'r'))
pool = Pool(processes=8)
partitions = chunks(lines, len(lines)/8)
results = pool.map(initial_map, partitions, 1)
因此,chunks函数会生成原始行集的子列表列表以提供给pool.map()
,然后它应该将这8个子列表交给8个不同的进程并通过映射器函数运行它们。当我运行它时,我可以看到我的所有8个核心达到峰值100%。然而它需要22-24秒。
当我简单地运行它(单个进程/线程)时:
lines = list(open("../../log.txt", 'r'))
results = initial_map(results)
大约需要相同的时间。 ~24秒。我只看到一个进程达到100%CPU。
我也试过让游戏池自行拆分并让映射器函数一次只处理一行,结果相似。
def initial_map(line):
processed = # process line (O^(1) operation)
return processed
if __name__ == "__main__":
lines = list(open("../../log.txt", 'r'))
pool = Pool(processes=8)
pool.map(initial_map, lines)
~22秒。
为什么会这样?并行化这应该会导致更快的结果,不是吗?
答案 0 :(得分:1)
如果在一次迭代中完成的工作量非常小,那么您只需花费很大一部分时间与子进程进行通信,这是很昂贵的。相反,尝试将更大的数据片段传递给处理函数。如下所示:
slices = (data[i:i+100] for i in range(0, len(data), 100)
def process_slice(data):
return [initial_data(x) for x in data]
pool.map(process_slice, slices)
# and then itertools.chain the output to flatten it
(没有我的补偿。所以不能给你一个完整的工作解决方案,也不能验证我说的话)
修改或查看@ubomb的问题的第3条评论。