随着计算机技术的发展,诸如GPU和超算平台等越来越发达,这些技术的本质其实并没有带来算法上的革新,之所以能够提升计算的速度和规模,很大程度上是因为分布式和并行计算的优势。这里我们介绍一个简单的python自带的多进程的代码实现,使用的是concurrent这个工具,同时我们也会介绍如何更好的配置多进程的资源。

concurrent使用示例

concurrent是python自带的一个多进程实现仓库,不需要额外的安装。这里我们先介绍一个没有多进程的示例代码:

import timedef sleep(seconds):time.sleep(seconds)if __name__ == '__main__':times = [1] * 10time0 = time.time()for t in times:sleep(t)time1 = time.time()print ('The time cost is: {}s'.format(time1 - time0))

这个代码的功能其实就是休眠10s的时间,也比较容易,我们可以看一下这个代码的执行结果:

[dechin@dechin-manjaro concurrent]$ python3 sleep.py
The time cost is: 10.014754295349121s

在我们统计时间的时候,发现会比10s的时间多出来一些,这部分时间不仅仅包含这个python程序执行的时间,跟时间的统计方式也有一定的关系,一般我们可以忽略这部分的gap时间。

我们假定上面这个程序中的sleep函数功能不是休眠1s的时间,而是执行一个耗时为1s的计算任务,而我们有很多的cpu,希望能够加速这个计算的过程,这个时候我们就需要用到多进程的技术,下面是修改为多进程之后的代码:

import concurrent.futures
import timedef sleep(seconds):time.sleep(seconds)if __name__ == '__main__':times = [1] * 10time0 = time.time()with concurrent.futures.ProcessPoolExecutor() as executor:executor.map(sleep, times)time1 = time.time()print ('The time cost is: {}s'.format(time1 - time0))

整个修改的方式也非常容易,就是把原代码中的for循环修改为concurrent的执行语句,让我们一起来看看执行的结果:

[dechin@dechin-manjaro concurrent]$ python3 concurrent_sleep.py
The time cost is: 2.0304219722747803s

从结果上我们可以看到,运行的时间从10s降低到了2s。这说明我们的多进程任务带来了非常显著的优化效果,至于为什么优化之后是2s而不是3s或者1s,这个问题将在下一个章节中进行介绍。

多进程的最佳配置

使用多进程的方案,能有多大的加速效果,很大程度上是依赖于硬件的。理论上来说,如果有n个cpu核,我们就可以实现n倍的加速。但是大部分情况下会受限于算法或者任务本身,跟n倍的加速之间有一定的gap。首先让我们用ipython来看看本地电脑上有多少个cpu:

[dechin@dechin-manjaro concurrent]$ ipython
Python 3.8.5 (default, Sep  4 2020, 07:30:14)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.19.0 -- An enhanced Interactive Python. Type '?' for help.In [1]: import psutilIn [2]: psutil.cpu_count(logical=False)
Out[2]: 4In [3]: psutil.cpu_count(logical=True)
Out[3]: 8

这里我们使用的是psutil这个库,而不是常用的os或者multiprocessing,这是因为可以更好的区分逻辑核与物理核。我们本地的电脑上有4个物理核,每个物理核实际上对应于2个逻辑核,因此一共是有8个逻辑核。也就是说,理论上我们最大可以加速8倍的算法执行时间。让我们通过配置和修改一些参数来测试验证一下:

import concurrent.futures
import time
import sysdef sleep(seconds):time.sleep(seconds)if __name__ == '__main__':if sys.argv[1] == '-t':times = [1] * int(sys.argv[2]) # 获取命令行的时间输入参数time0 = time.time()with concurrent.futures.ProcessPoolExecutor() as executor:executor.map(sleep, times)time1 = time.time()print ('The time cost is: {}s'.format(time1 - time0))

在这个示例中,为了方便调整,我们把总的休眠时间定为命令行的输入参数,使用的是sys.argv这个函数来获取,注意获取到的参数是字符串格式的。这串代码的执行方法和执行结果如下所示:

[dechin@dechin-manjaro concurrent]$ python3 concurrent_sleep.py -t 16
The time cost is: 2.0304934978485107s

在上面的执行结果中,我们发现原本需要16s的休眠任务,在多进程场景下被加速到了2s,刚好符合我们对逻辑核的加速倍数的预期。但是前面提到,能否加速逻辑核的倍数,跟任务本身的算法也有关系。比如在本用例中,如果算法分配的结果就是需要17个子算法来进行实现,那么在每个逻辑核上面执行了2次的休眠任务之后,又有一个逻辑核需要再执行1次休眠任务,而此时其他的逻辑核都需要等待这个执行任务的逻辑核的任务结束。具体的执行结果如下所示:

[dechin@dechin-manjaro concurrent]$ python3 concurrent_sleep.py -t 17
The time cost is: 3.0313029289245605s

这个结果也验证了我们此前的预想,因为16s的任务执行需要2s的时间,而执行完16s的任务之后,又需要等待剩下的一个1s时长的任务执行完毕,总耗时3s。这里我们没有配置max_worker的情况下,会按照系统中最高的逻辑核数来进行多进程的任务分配,但是在实际场景中我们需要考虑多种因素的限制,如内存和进程数的均衡配置(在大内存任务中,如果进程全开,有可能导致内存不足的问题)。只有在满足所有系统约束条件的情况下,才能发挥硬件最好的性能。在下面的代码中我们将给出如何配置执行任务的核数的方案:

import concurrent.futures
import time
import sysdef sleep(seconds):time.sleep(seconds)if __name__ == '__main__':if sys.argv[1] == '-t':times = [1] * int(sys.argv[2])time0 = time.time()with concurrent.futures.ProcessPoolExecutor(max_workers=4) as executor:executor.map(sleep, times)time1 = time.time()print ('The time cost is: {}s'.format(time1 - time0))

配置方法也很容易,就是在ProcessPoolExecutor函数的入参中引入max_worker,这里我们先将最大使用的核数设置为4,再来重新看一下上述用例的执行结果:

[dechin@dechin-manjaro concurrent]$ python3 concurrent_sleep.py -t 16
The time cost is: 4.032958030700684s
[dechin@dechin-manjaro concurrent]$ python3 concurrent_sleep.py -t 17
The time cost is: 5.032677173614502s

对于16s的任务,因为开了4个核的并行,因此在4s的时间内完成了任务。而17s的任务,同样是需要多等待1s的时间,总耗时为5s。

获取返回值

如果任务可以互相独立的去执行,互相之间并不需要通信,那自然是最理想的情况。但是更多的情况下,我们是要收集各个进程的返回值的,通过这个返回值,在各个进程之间进行通信。而在concurrent的情况下,map函数的返回值直接就是所有进程的返回值所组成的列表,这更加方便了我们的任务执行。

'''
学习中遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''import concurrent.futures
import time
import sysdef sleep(seconds):time.sleep(seconds)return secondsif __name__ == '__main__':if sys.argv[1] == '-t':times = [1] * int(sys.argv[2])time0 = time.time()with concurrent.futures.ProcessPoolExecutor(max_workers=4) as executor:results = executor.map(sleep, times)print ('The total sleep cpu time is: {}s'.format(sum(results)))time1 = time.time()print ('The time cost is: {}s'.format(time1 - time0))

在这个用例中,我们将map函数的结果存储到results这一参数中,最后对results进行求和的操作,这个简单的示例中,返回的结果实际上就是总的输入的休眠时间。执行结果如下所示:

[dechin@dechin-manjaro concurrent]$ python3 concurrent_sleep.py -t 16
The total sleep cpu time is: 16s
The time cost is: 4.034112930297852s

可以看到,所有的返回值被成功的获取到。

总结

多进程技术是独立于算法任务本身的一种优化技术,通过python中的concurrent库,我们可以非常容易的实现多进程的任务,用来优化已有的算法。这里我们也给出了一些多进程配置信息的参考方案,在GPU和超算相关的领域上,都能够发挥较大的用途。

python3教程:用concurrent执行多进程任务的方法相关推荐

  1. python多进程怎么样_Python执行多进程任务的方法

    Python的多进程可以借助from multiprocessing import Pool来实现. 简而言之分为这样几步: 导入包from multiprocessing import Pool 编 ...

  2. python3.6卸载教程_Python3.6安装卸载、执行命令、执行py文件的方法详解

    开发一个功能,C/C++可能要500行代码,Java可能需要200行代码,然而Python可能需要50行代码,虽然代码少,可能开发的飞起,但是这其实是已牺牲运行效率位代价的,可能C只要1秒,Java需 ...

  3. Python3.2+ 的 concurrent.futures 模块,利用 multiprocessing 实现高并发。

    From:https://www.cnblogs.com/weihengblog/p/9812110.html concurrent.futures 官方文档:https://docs.python. ...

  4. python3教程-Python3 教程

    Python3 教程 Python的3.0版本,常被称为Python 3000,或简称Py3k.相对于Python的早期版本,这是一个较大的升级.为了不带入过多的累赘,Python 3.0在设计的时候 ...

  5. Python3教程——3、Python3 用什么IDE开发工具好呢

    和小名一起学Python Python3教程--Python3 用什么IDE开发工具 这也许是学习一门语言时大家都会问的一个问题,其实我个人认为无所谓哪个最好,关键在于哪个用着顺手,方便.还有很多人乐 ...

  6. Linux安装python3教程

    Linux安装python3教程 原文地址:https://program-park.github.io/2021/03/25/python_4/ 我这里用的是CentOS7.2系统以及python3 ...

  7. python3教程简介

    python3教程&简介 Python 3 教程 查看 Python 版本 第一个Python3.x程序 Python3 简介 Python 发展历史 Python 特点 Python 应用 ...

  8. Python爬虫实战——爬取RUNOOB.COM的Python3教程

    说明 关于Python开发环境搭建,可参考博主的另一篇博文-Visual Studio 2017搭配OpenCV之Python环境,省去其中的OpenCV配置及安装即可.另外,在做Python爬虫项目 ...

  9. 关于liaoxuefeng的python3教程实战第四天

    关于liaoxuefeng的python3教程 实战第四天. 地址:http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df ...

最新文章

  1. java datetime now_相当于C#的DateTime.Now在Java中?
  2. 网站如何接入支付宝(转)
  3. UVA11991第k次出现的v的下标
  4. @清晰掉 GNU C __attribute__
  5. Nginx的启动、停止
  6. 自建zookeeper测试dubbo
  7. Python【7】-数据分析准备
  8. 计算机网络与通信基础知识,计算机网络与通信基础/谢雨飞
  9. 如何判断网通、电信、铁通IP地址分配段
  10. 小容量单片机生成pdf文件
  11. 零配置 之Spring基于Java类定义Bean配置元数据
  12. python中多条件语句_Python中的带条件语句
  13. 均值文件转matlab,LMD局域均值分解的matlab程序及示例代码
  14. WEB开发技术 知识点总结
  15. Project2007工具栏没有Pert分析按钮
  16. 搭建魔兽世界服务端编译环境
  17. 微信好友删除了怎么找回来
  18. Google earth 生成研究区适量边界(研究区边界从哪来?)
  19. java获取月和日_java – 如何获取dateformat来大写月和日
  20. SparkStreaming通过读取文件动态黑名单过滤

热门文章

  1. Retinex、log对数变换、直方图均衡化区别,边缘增强Retinex算法与拉普拉斯算法联系、均衡化与亮度调节算法、大津阈值计算
  2. const int *,const int * const和int const *之间的区别
  3. 正在被二次元改造的中国城市
  4. java中如何反编译class文件
  5. 【转载】Visual Studio 2017各版本安装包离线下载、安装全解析
  6. 转载:Java语言学习
  7. 从51开始的单片机之旅(一)----流水灯、矩形键盘、电子时钟
  8. 源码编译安装git过程记录
  9. 数据库设计阶段和三个重要的设计模型
  10. 成功案例丨荣联助力中科院上海有机所冷冻电镜大数据计算系统建设