Python几类并行方法比较
1、baseline: for loop
最传统的方法即为使用 for 循环,进行串行处理:
with Timer(print_tmpl='for loop takes {:.1f} seconds'):
data_infos = []
for line in lines:
info = load_culane_ann(line)
data_infos.append(info)
del data_infos
得到的输出为:
for loop tqdm takes 9.4 seconds
2、map
python 的 map 方法可以很简单地替换掉 for 循环,但本质也是串行处理:
with Timer(print_tmpl='map takes {:.1f} seconds'):
data_infos = map(load_culane_ann, lines)
data_infos = list(data_infos)
del data_infos
得到的输出为:
map takes 9.2 seconds
3、multiprocessing
multiprocessing 是 python 里的多进程包,通过它,我们可以在 python 程序里建立多进程来执行任务,从而进行并行计算。
multiprocessing 有很多复杂的用法,本文着眼于最简单方便的改造并行化,所以只使介绍最简单的方法。
(1) multiprocessing.Pool
作用于进程,可以指定进程数,默认cpu数量
from multiprocessing import Pool
with Timer(print_tmpl='Pool() takes {:.1f} seconds'):
with Pool() as p:
# with Pool(4) as p: # 指定4个进程
data_infos = p.map(load_culane_ann, lines)
del data_infos
得到的输出为:
Pool() takes 2.5 seconds
Pool(4) takes 2.9 seconds
Pool(8) takes 1.8 seconds
Pool(16) takes 1.4 seconds
Pool(32) takes 1.6 seconds
(2) multiprocessing.dummy.Pool
作用于线程,用法和上面一样,但是在我的任务中会更慢:
from multiprocessing.dummy import Pool as ThreadPool
with Timer(print_tmpl='ThreadPool() takes {:.1f} seconds'):
with ThreadPool() as p:
# with TreadPool(4) as p: # 指定4个线程
data_infos = p.map(load_culane_ann, lines)
del data_infos
得到的输出为:
ThreadPool() takes 37.4 seconds
ThreadPool(4) takes 29.4 seconds
ThreadPool(8) takes 33.3 seconds
ThreadPool(16) takes 34.4 seconds
4、p_tqdm
p_tqdm 是对 pathos.multiprocessing and tqdm 的包装库,可以对方便地对并行处理显示进度条,方法主要有如下几种:
并行 map:
p_map - 并行有序 map
p_umap - 并行无序 map
串行 map:
t_map - 串行有序 map
使用方法和 map 一样,这里就列举一种:
with Timer(print_tmpl='p_map takes {:.1f} seconds'):
data_infos = p_map(load_culane_ann, lines)
del data_infos
得到的输出为:
100%|██████████████████████████████████████| 88880/88880 [05:28<00:00, 270.19it/s]
p_map takes 329.7 seconds
100%|██████████████████████████████████████| 88880/88880 [05:33<00:00, 266.75it/s]
p_umap takes 334.4 seconds
100%|█████████████████████████████████████| 88880/88880 [00:09<00:00, 9530.67it/s]
t_map takes 9.3 seconds
结论:
几种顺序执行方案,时间差不多:baseline for loop、map、t_map;
基于进程的并行化 Pool,和基于线程的并行化 ThreadPool,具体哪个更快要根据具体情况实验分析,在本文中,因为数据放在ssd上,数据读取不是瓶颈,主要耗时在cpu处理上,所以基于进程的速度更快,基于线程的相反非常慢;相反如果是io密集型任务,数据读取是瓶颈,那么可能基于线程的 ThreadPool会更快;
进程数或者线程数设置得太大,或者太小,都会导致运行时间变长,可以根据自己的任务以及机器情况,试验设置合适的进程数;
p_tqdm 库中的 p_map、p_umap 可以给并行处理显示进度条,但是运行时间变得太长了,不建议使用,如果想显示进度条,可以用 t_map 顺序处理,会更快,或者直接使用 tqdm 库;
See https://zhuanlan.zhihu.com/p/559070673?utm_id=0