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利用lxml读写xml格式的文件
Aug 10 Python
Python简单实现查找一个字符串中最长不重复子串的方法
Mar 26 Python
Python基于jieba库进行简单分词及词云功能实现方法
Jun 16 Python
Python实现通过继承覆盖方法示例
Jul 02 Python
jupyter notebook 中输出pyecharts图实例
Apr 23 Python
Python Django Vue 项目创建过程详解
Jul 29 Python
python实现按首字母分类查找功能
Oct 31 Python
在Python中字符串、列表、元组、字典之间的相互转换
Nov 15 Python
PyQt5中多线程模块QThread使用方法的实现
Jan 31 Python
浅谈matplotlib中FigureCanvasXAgg的用法
Jun 16 Python
如何用Python和JS实现的Web SSH工具
Feb 23 Python
python基于tkinter实现gif录屏功能
May 19 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
Http 1.1 Etag 与 Last-Modified提高php效率
2008/01/10 PHP
php中session定期自动清理的方法
2015/11/12 PHP
PHP+redis实现添加处理投票的方法
2015/11/14 PHP
详解提高使用Java反射的效率方法
2019/04/29 PHP
深入解析PHP底层机制及相关原理
2020/12/11 PHP
javascript 图片上一张下一张链接效果代码
2010/03/12 Javascript
ajax处理php返回json数据的实例代码
2013/01/24 Javascript
js判断运行jsp页面的浏览器类型以及版本示例
2013/10/30 Javascript
js实现百度联盟中一款不错的图片切换效果完整实例
2015/03/04 Javascript
jQuery easyui的validatebox校验规则扩展及easyui校验框validatebox用法
2016/01/18 Javascript
jquery实现全选和全不选功能效果的实现代码【推荐】
2016/05/05 Javascript
js判断复选框是否选中及选中个数的实现代码
2016/05/30 Javascript
实例讲解JavaScript中instanceof运算符的用法
2016/06/08 Javascript
BootStrap数据表格实例代码
2017/09/13 Javascript
jQuery中过滤器的基本用法示例
2017/10/11 jQuery
vue2.0父子组件间传递数据的方法
2018/08/16 Javascript
npm配置国内镜像资源+淘宝镜像的方法
2018/09/07 Javascript
使用electron实现百度网盘悬浮窗口功能的示例代码
2018/10/24 Javascript
深入讲解Python中面向对象编程的相关知识
2015/05/25 Python
python实现汉诺塔算法
2021/03/01 Python
Python中字符串String的基本内置函数与过滤字符模块函数的基本用法
2019/05/27 Python
python3.6 如何将list存入txt后再读出list的方法
2019/07/02 Python
详解Python中的正斜杠与反斜杠
2019/08/09 Python
简单瞅瞅Python vars()内置函数的实现
2019/09/27 Python
如何使用Python脚本实现文件拷贝
2019/11/20 Python
Django Serializer HiddenField隐藏字段实例
2020/03/31 Python
k-means 聚类算法与Python实现代码
2020/06/01 Python
pytorch VGG11识别cifar10数据集(训练+预测单张输入图片操作)
2020/06/24 Python
Python2及Python3如何实现兼容切换
2020/09/01 Python
如何使用python-opencv批量生成带噪点噪线的数字验证码
2020/12/21 Python
解决tensorflow模型压缩的问题_踩坑无数,总算搞定
2021/03/02 Python
AmazeUI的下载配置与Helloworld的实现
2020/08/19 HTML / CSS
快递员岗位职责
2014/09/12 职场文书
2014年城管工作总结
2014/11/20 职场文书
检讨书怎么写
2015/01/23 职场文书
2016年教师新年寄语
2015/08/18 职场文书