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之入门(五)缩进和选择
May 27 Python
Python list操作用法总结
Nov 10 Python
简单谈谈Python中的反转字符串问题
Oct 24 Python
python3+PyQt5+Qt Designer实现堆叠窗口部件
Apr 20 Python
详谈Pandas中iloc和loc以及ix的区别
Jun 08 Python
Python 通过调用接口获取公交信息的实例
Dec 17 Python
Django 接收Post请求数据,并保存到数据库的实现方法
Jul 12 Python
python按行读取文件并找出其中指定字符串
Aug 08 Python
Django用数据库表反向生成models类知识点详解
Mar 25 Python
浅谈python 中的 type(), dtype(), astype()的区别
Apr 09 Python
Python 抓取数据存储到Redis中的操作
Jul 16 Python
Python环境搭建过程从安装到Hello World
Feb 05 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
改造一台复古桌面收音机
2021/03/02 无线电
YII框架学习笔记之命名空间、操作响应与视图操作示例
2019/04/30 PHP
newxtree.js代码
2007/03/13 Javascript
淘宝搜索框效果实现分析
2011/03/05 Javascript
javascript学习笔记(十六) 系统对话框(alert、confirm、prompt)
2012/06/20 Javascript
onkeypress字符按键兼容所有浏览器使用介绍
2013/04/24 Javascript
js中settimeout方法加参数的使用实例
2014/02/27 Javascript
javascript匀速运动实现方法分析
2016/01/08 Javascript
获取JavaScript异步函数的返回值
2016/12/21 Javascript
canvas红包照片实例分享
2017/02/28 Javascript
JavaScript 中调用 Kotlin 方法实例详解
2017/06/09 Javascript
jQuery Easyui Treegrid实现显示checkbox功能
2017/08/08 jQuery
JS实现移动端整屏滑动的实例代码
2017/11/10 Javascript
详解vue-cli 接口代理配置
2017/12/13 Javascript
微信小程序中实现手指缩放图片的示例代码
2018/03/13 Javascript
JavaScript键盘事件常见用法实例分析
2019/01/03 Javascript
js删除数组中某几项的方法总结
2019/01/16 Javascript
Vue传参一箩筐(页面、组件)
2019/04/04 Javascript
原生JS利用transform实现banner的无限滚动示例代码
2020/06/15 Javascript
Python中利用sorted()函数排序的简单教程
2015/04/27 Python
Python入门之三角函数全解【收藏】
2017/11/08 Python
python Opencv将图片转为字符画
2021/02/19 Python
python代码过长的换行方法
2018/07/19 Python
python 文件查找及内容匹配方法
2018/10/25 Python
python 利用for循环 保存多个图像或者文件的实例
2018/11/09 Python
django 自定义过滤器的实现
2019/02/26 Python
浅谈Python中range与Numpy中arange的比较
2020/03/11 Python
CSS3的常见transformation图形变化用法小结
2016/05/13 HTML / CSS
日本土著品牌,综合型购物网站:Cecile
2016/08/23 全球购物
科颜氏香港官方网店:Kiehl’s香港
2021/03/07 全球购物
军训生自我鉴定范文
2013/12/27 职场文书
讲文明树新风演讲稿
2014/05/12 职场文书
开展批评与自我批评心得体会
2014/10/17 职场文书
2015医德医风个人工作总结
2015/04/02 职场文书
会议承办单位欢迎词
2015/09/30 职场文书
实习员工转正的评语汇总,以备不时之需
2019/12/17 职场文书