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 相关文章推荐
Django中使用group_by的方法
May 26 Python
详解python 发送邮件实例代码
Dec 22 Python
Python中协程用法代码详解
Feb 10 Python
pandas对指定列进行填充的方法
Apr 11 Python
python库lxml在linux和WIN系统下的安装
Jun 24 Python
python实现简单tftp(基于udp协议)
Jul 30 Python
对python 操作solr索引数据的实例详解
Dec 07 Python
在scrapy中使用phantomJS实现异步爬取的方法
Dec 17 Python
详解python中的模块及包导入
Aug 30 Python
python爬虫库scrapy简单使用实例详解
Feb 10 Python
使用keras实现孪生网络中的权值共享教程
Jun 11 Python
Django基于Models定制Admin后台实现过程解析
Nov 11 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
PHP中读取照片exif信息的方法
2014/08/20 PHP
Yii2中使用join、joinwith多表关联查询
2016/06/30 PHP
JavaScript 事件的一些重要说明
2009/10/25 Javascript
JavaScript ECMA-262-3 深入解析.第三章.this
2011/09/28 Javascript
采用call方式实现js继承
2014/05/20 Javascript
使用AngularJS编写较为优美的JavaScript代码指南
2015/06/19 Javascript
JS实现可直接显示网页代码运行效果的HTML代码预览功能实例
2015/08/06 Javascript
JavaScript快速切换繁体中文和简体中文的方法及网站支持简繁体切换的绝招
2016/03/07 Javascript
浅谈JS正则表达式的RegExp对象和括号的使用
2016/07/28 Javascript
JavaScript两个变量交换值的实现方法
2017/03/01 Javascript
nodejs中向HTTP响应传送进程的输出
2017/03/19 NodeJs
Nodejs读取文件时相对路径的正确写法(使用fs模块)
2017/04/27 NodeJs
微信小程序联网请求的轮播图
2017/07/07 Javascript
checkbox:click事件触发span元素内容改变的方法
2017/09/11 Javascript
vue+elementUI实现表格关键字筛选高亮
2020/10/26 Javascript
基于Element封装一个表格组件tableList的使用方法
2020/06/29 Javascript
Python学习资料
2007/02/08 Python
python实现sublime3的less编译插件示例
2014/04/27 Python
python实现简单的TCP代理服务器
2014/10/08 Python
Python实现设置windows桌面壁纸代码分享
2015/03/28 Python
Python实现的科学计算器功能示例
2017/08/04 Python
Python中%是什么意思?python中百分号如何使用?
2018/03/20 Python
wxPython的安装与使用教程
2018/08/31 Python
对python3中pathlib库的Path类的使用详解
2018/10/14 Python
pandas每次多Sheet写入文件的方法
2018/12/10 Python
python-opencv 将连续图片写成视频格式的方法
2019/01/08 Python
python实现磁盘日志清理的示例
2020/11/05 Python
前端面试必备之CSS3的新特性
2017/09/05 HTML / CSS
Lookfantastic葡萄牙官方网站:欧洲第一大化妆品零售商
2018/03/17 全球购物
ASICS印度官方网站:日本专业运动品牌
2020/06/20 全球购物
幼儿园优秀班主任事迹材料
2014/05/14 职场文书
庆元旦活动总结
2014/07/09 职场文书
我的中国心演讲稿
2014/09/04 职场文书
公司新人试用期自我评价
2014/09/17 职场文书
2015年六一儿童节活动总结
2015/02/11 职场文书
使用nginx动态转换图片大小生成缩略图
2021/03/31 Servers