• 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    得到的输出为:

    for loop tqdm takes 9.4 seconds
    
    • 1

    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
    
    • 1
    • 2
    • 3
    • 4

    得到的输出为:

    map takes 9.2 seconds
    
    • 1

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    得到的输出为:

     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
    
    • 1
    • 2
    • 3
    • 4
    • 5

    (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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    得到的输出为:

     ThreadPool() takes 37.4 seconds
     ThreadPool(4) takes 29.4 seconds
     ThreadPool(8) takes 33.3 seconds
     ThreadPool(16) takes 34.4 seconds
    
    • 1
    • 2
    • 3
    • 4

    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
    
    • 1
    • 2
    • 3
    得到的输出为:
    
     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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    结论:

    几种顺序执行方案,时间差不多: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

  • 相关阅读:
    【Spring事务底层实现原理】
    网页js版音频数字信号处理:H5录音+特定频率信号的特征分析和识别提取
    MySQL如何在不知道密码的情况下知道并修改密码
    基于AntDesign vue的自定义文件上传
    龙迅LT8912B 单通道MIPIDSI桥接LVDS+HDMI(1.4)同显点屏LVDS,加环出一路HDMI
    Three.js快速入门
    模型降阶方法之 POD
    梳理Langchain-Chatchat知识库API接口
    Linux网络编程 I/O模型和服务器模型
    工作常用之Hive 调优【四】HQL 语法优化
  • 原文地址:https://blog.csdn.net/y15520833229/article/details/134460679