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 相关文章推荐
Python中pip安装非PyPI官网第三方库的方法
Jun 02 Python
Django 如何获取前端发送的头文件详解(推荐)
Aug 15 Python
python中int与str互转方法
Jul 02 Python
Python django使用多进程连接mysql错误的解决方法
Oct 08 Python
python如何获取当前文件夹下所有文件名详解
Jan 25 Python
pyinstaller打包多个py文件和去除cmd黑框的方法
Jun 21 Python
Django 路由控制的实现
Jul 17 Python
python实现银行实战系统
Feb 26 Python
Pycharm IDE的安装和使用教程详解
Apr 30 Python
如何利用pycharm进行代码更新比较
Nov 04 Python
Python机器学习之PCA降维算法详解
May 19 Python
学会Python数据可视化必须尝试这7个库
Jun 16 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
星际原理概述
2020/03/04 星际争霸
php与php MySQL 之间的关系
2009/07/17 PHP
php无限分类且支持输出树状图的详细介绍
2013/06/19 PHP
高性能PHP框架Symfony2经典入门教程
2014/07/08 PHP
PHP将Excel导入数据库及数据库数据导出至Excel的方法
2015/06/24 PHP
PHP 等比例缩放图片详解及实例代码
2016/09/18 PHP
Jquery 基础学习笔记
2009/05/29 Javascript
jQuery JSON实现无刷新三级联动实例探讨
2013/05/28 Javascript
JS 排序输出实现table行号自增前端动态生成的tr
2014/08/13 Javascript
jQuery图片轮播功能实例代码
2017/01/29 Javascript
详解Jquery EasyUI tree 的异步加载(遍历指定文件夹,根据文件夹内的文件生成tree)
2017/02/11 Javascript
javascript 删除数组元素和清空数组的简单方法
2017/02/24 Javascript
es6的数字处理的方法(5个)
2017/03/16 Javascript
JS中Safari浏览器中的Date
2017/07/17 Javascript
angularjs中$http异步上传Excel文件方法
2018/02/23 Javascript
JavaScript数组,JSON对象实现动态添加、修改、删除功能示例
2018/05/26 Javascript
Vue源码之关于vm.$delete()/Vue.use()内部原理详解
2019/05/01 Javascript
javascript简单实现深浅拷贝过程详解
2019/10/08 Javascript
详解微信小程序(Taro)手动埋点和自动埋点的实现
2021/03/02 Javascript
Python 时间操作例子和时间格式化参数小结
2014/04/24 Python
Django的数据模型访问多对多键值的方法
2015/07/21 Python
Windows平台Python连接sqlite3数据库的方法分析
2017/07/12 Python
python引入导入自定义模块和外部文件的实例
2017/07/24 Python
Tensorflow分类器项目自定义数据读入的实现
2019/02/05 Python
为什么你还不懂得怎么使用Python协程
2019/05/13 Python
利用keras加载训练好的.H5文件,并实现预测图片
2020/01/24 Python
解决windows上安装tensorflow时报错,“DLL load failed: 找不到指定的模块”的问题
2020/05/20 Python
Python 按比例获取样本数据或执行任务的实现代码
2020/12/03 Python
自荐书格式
2013/12/01 职场文书
商务英语应届生自我鉴定
2013/12/08 职场文书
降消项目实施方案
2014/03/30 职场文书
企业贷款委托书格式
2014/09/12 职场文书
团员个人年度总结
2015/02/26 职场文书
护士实习自荐信
2015/03/06 职场文书
2015年公务员试用期工作总结
2015/05/28 职场文书
Nginx的gzip相关介绍
2022/05/11 Servers