Python 多进程、多线程效率对比


Posted in Python onNovember 19, 2020

Python 界有条不成文的准则: 计算密集型任务适合多进程,IO 密集型任务适合多线程。本篇来作个比较。

通常来说多线程相对于多进程有优势,因为创建一个进程开销比较大,然而因为在 python 中有 GIL 这把大锁的存在,导致执行计算密集型任务时多线程实际只能是单线程。而且由于线程之间切换的开销导致多线程往往比实际的单线程还要慢,所以在 python 中计算密集型任务通常使用多进程,因为各个进程有各自独立的 GIL,互不干扰。

而在 IO 密集型任务中,CPU 时常处于等待状态,操作系统需要频繁与外界环境进行交互,如读写文件,在网络间通信等。在这期间 GIL 会被释放,因而就可以使用真正的多线程。

以上是理论,下面做一个简单的模拟测试: 大量计算用 math.sin() + math.cos() 来代替,IO 密集型用 time.sleep() 来模拟。 在 Python 中有多种方式可以实现多进程和多线程,这里一并纳入看看是否有效率差异:

  1. 多进程: joblib.multiprocessing, multiprocessing.Pool, multiprocessing.apply_async, concurrent.futures.ProcessPoolExecutor
  2. 多线程: joblib.threading, threading.Thread, concurrent.futures.ThreadPoolExecutor
from multiprocessing import Pool
from threading import Thread
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
import time, os, math
from joblib import Parallel, delayed, parallel_backend


def f_IO(a): # IO 密集型
 time.sleep(5)

def f_compute(a): # 计算密集型
 for _ in range(int(1e7)):
  math.sin(40) + math.cos(40)
 return

def normal(sub_f):
 for i in range(6):
  sub_f(i)
 return

def joblib_process(sub_f):
 with parallel_backend("multiprocessing", n_jobs=6):
  res = Parallel()(delayed(sub_f)(j) for j in range(6))
 return


def joblib_thread(sub_f):
 with parallel_backend('threading', n_jobs=6):
  res = Parallel()(delayed(sub_f)(j) for j in range(6))
 return

def mp(sub_f):
 with Pool(processes=6) as p:
  res = p.map(sub_f, list(range(6)))
 return

def asy(sub_f):
 with Pool(processes=6) as p:
  result = []
  for j in range(6):
   a = p.apply_async(sub_f, args=(j,))
   result.append(a)
  res = [j.get() for j in result]

def thread(sub_f):
 threads = []
 for j in range(6):
  t = Thread(target=sub_f, args=(j,))
  threads.append(t)
  t.start()
 for t in threads:
  t.join()

def thread_pool(sub_f):
 with ThreadPoolExecutor(max_workers=6) as executor:
  res = [executor.submit(sub_f, j) for j in range(6)]

def process_pool(sub_f):
 with ProcessPoolExecutor(max_workers=6) as executor:
  res = executor.map(sub_f, list(range(6)))

def showtime(f, sub_f, name):
 start_time = time.time()
 f(sub_f)
 print("{} time: {:.4f}s".format(name, time.time() - start_time))

def main(sub_f):
 showtime(normal, sub_f, "normal")
 print()
 print("------ 多进程 ------")
 showtime(joblib_process, sub_f, "joblib multiprocess")
 showtime(mp, sub_f, "pool")
 showtime(asy, sub_f, "async")
 showtime(process_pool, sub_f, "process_pool")
 print()
 print("----- 多线程 -----")
 showtime(joblib_thread, sub_f, "joblib thread")
 showtime(thread, sub_f, "thread")
 showtime(thread_pool, sub_f, "thread_pool")


if __name__ == "__main__":
 print("----- 计算密集型 -----")
 sub_f = f_compute
 main(sub_f)
 print()
 print("----- IO 密集型 -----")
 sub_f = f_IO
 main(sub_f)

结果:

----- 计算密集型 -----
normal time: 15.1212s

------ 多进程 ------
joblib multiprocess time: 8.2421s
pool time: 8.5439s
async time: 8.3229s
process_pool time: 8.1722s

----- 多线程 -----
joblib thread time: 21.5191s
thread time: 21.3865s
thread_pool time: 22.5104s



----- IO 密集型 -----
normal time: 30.0305s

------ 多进程 ------
joblib multiprocess time: 5.0345s
pool time: 5.0188s
async time: 5.0256s
process_pool time: 5.0263s

----- 多线程 -----
joblib thread time: 5.0142s
thread time: 5.0055s
thread_pool time: 5.0064s

上面每一方法都统一创建6个进程/线程,结果是计算密集型任务中速度:多进程 > 单进程/线程 > 多线程, IO 密集型任务速度: 多线程 > 多进程 > 单进程/线程。

以上就是Python 多进程、多线程效率比较的详细内容,更多关于Python 多进程、多线程的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
在Mac OS上搭建Python的开发环境
Dec 24 Python
tensorflow中next_batch的具体使用
Feb 02 Python
tensorflow1.0学习之模型的保存与恢复(Saver)
Apr 23 Python
Python运维开发之psutil库的使用详解
Oct 18 Python
Django如何实现网站注册用户邮箱验证功能
Aug 14 Python
pip install python 快速安装模块的教程图解
Oct 08 Python
python实现WebSocket服务端过程解析
Oct 18 Python
Python 实现自动完成A4标签排版打印功能
Apr 09 Python
Python字典fromkeys()方法使用代码实例
Jul 20 Python
Python异常类型以及处理方法汇总
Jun 05 Python
Python一些基本的图像操作和处理总结
Jun 23 Python
Python的三个重要函数详解
Jan 18 Python
Python导入父文件夹中模块并读取当前文件夹内的资源
Nov 19 #Python
Pytorch实验常用代码段汇总
Nov 19 #Python
Ubuntu配置Pytorch on Graph (PoG)环境过程图解
Nov 19 #Python
python基于pygame实现飞机大作战小游戏
Nov 19 #Python
Python numpy大矩阵运算内存不足如何解决
Nov 19 #Python
python3 os进行嵌套操作的实例讲解
Nov 19 #Python
如何创建一个Flask项目并进行简单配置
Nov 18 #Python
You might like
shopex主机报错误请求解决方案(No such file or directory)
2011/12/27 PHP
php读取二进制流(C语言结构体struct数据文件)的深入解析
2013/06/13 PHP
免费手机号码归属地API查询接口和PHP使用实例分享
2014/04/10 PHP
ThinkPHP通过AJAX返回JSON的两种实现方法
2014/12/18 PHP
PHP实现随机发放扑克牌
2020/04/21 PHP
使用jquery选择器如何获取父级元素、同级元素、子元素
2014/05/14 Javascript
node.js中的buffer.write方法使用说明
2014/12/10 Javascript
JavaScript获取表单enctype属性的方法
2015/04/02 Javascript
javascript实现禁止复制网页内容汇总
2015/12/30 Javascript
分析js闭包引起的事件注册问题
2016/03/29 Javascript
Bootstrap栅格系统的使用和理解2
2016/12/14 Javascript
Bootstrap实现的表格合并单元格示例
2018/02/06 Javascript
jQuery插件jsonview展示json数据
2018/05/26 jQuery
vuejs实现标签选项卡动态更改css样式的方法
2018/05/31 Javascript
Cordova(ionic)项目实现双击返回键退出应用
2019/09/17 Javascript
解决layUI的页面显示不全的问题
2019/09/20 Javascript
Taro UI框架开发小程序实现左滑喜欢右滑不喜欢效果的示例代码
2020/05/18 Javascript
vscode 使用Prettier插件格式化配置使用代码详解
2020/08/10 Javascript
python计算一个序列的平均值的方法
2015/07/11 Python
Python检测网站链接是否已存在
2016/04/07 Python
使用Django简单编写一个XSS平台的方法步骤
2019/03/25 Python
Python绘制频率分布直方图的示例
2019/07/08 Python
Python zip函数打包元素实例解析
2019/12/11 Python
Django基于客户端下载文件实现方法
2020/04/21 Python
Scrapy模拟登录赶集网的实现代码
2020/07/07 Python
python实现扫雷游戏的示例
2020/10/20 Python
快速解决pymongo操作mongodb的时区问题
2020/12/05 Python
call在Python中改进数列的实例讲解
2020/12/09 Python
matplotlib 画动态图以及plt.ion()和plt.ioff()的使用详解
2021/01/05 Python
如何减少垃圾回收让内存更加有效使用
2013/10/18 面试题
2015年打非治违工作总结
2015/04/02 职场文书
开国大典观后感
2015/06/04 职场文书
2015年国庆节标语大全
2015/07/30 职场文书
交通安全宣传标语(100条)
2019/08/22 职场文书
python基础之停用词过滤详解
2021/04/21 Python
为什么RedisCluster设计成16384个槽
2021/09/25 Redis