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函数式编程
Jun 09 Python
Python2.x版本中基本的中文编码问题解决
Oct 12 Python
Python+Selenium自动化实现分页(pagination)处理
Mar 31 Python
python基础练习之几个简单的游戏
Nov 10 Python
Python提取特定时间段内数据的方法实例
Apr 01 Python
使用TensorFlow实现简单线性回归模型
Jul 19 Python
django-xadmin根据当前登录用户动态设置表单字段默认值方式
Mar 13 Python
使用Django实现把两个模型类的数据聚合在一起
Mar 28 Python
基于python实现计算且附带进度条代码实例
Mar 31 Python
django 多数据库及分库实现方式
Apr 01 Python
详解tensorflow2.x版本无法调用gpu的一种解决方法
May 25 Python
Python APScheduler执行使用方法详解
Dec 10 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 SQLite类
2009/05/07 PHP
yii2使用gridView实现下拉列表筛选数据
2017/04/10 PHP
php读取出一个文件夹及其子文件夹下所有文件的方法示例
2017/06/15 PHP
基于ThinkPHP5.0实现图片上传插件
2017/09/25 PHP
告诉大家什么是JSON
2008/06/10 Javascript
JavaScript Undefined,Null类型和NaN值区别
2008/10/22 Javascript
js 手机号码合法性验证代码集合
2012/09/29 Javascript
百度地图api应用标注地理位置信息(js版)
2013/02/01 Javascript
javascript获取隐藏dom的宽高 具体实现
2013/07/14 Javascript
JS.findElementById()使用介绍
2013/09/21 Javascript
jQuery中选择器小问题(新人难免遇到)
2014/03/31 Javascript
jQuery实现倒计时按钮功能代码分享
2014/09/03 Javascript
Node.js开源应用框架HapiJS介绍
2015/01/14 Javascript
JS原生轮播图的简单实现(推荐)
2017/07/22 Javascript
JS实现图片放大镜插件详解
2017/11/06 Javascript
详解webpack3编译兼容IE8的正确姿势
2017/12/21 Javascript
element vue validate验证名称重复 输入框与后台重复验证 特殊字符 字符长度 及注意事项小结【实例代码】
2018/11/20 Javascript
小程序实现新用户判断并跳转激活的方法
2019/05/20 Javascript
[02:55]2018DOTA2国际邀请赛勇士令状不朽珍藏Ⅲ饰品一览
2018/08/01 DOTA
浅谈python 四种数值类型(int,long,float,complex)
2016/06/08 Python
Python变量和字符串详解
2017/04/29 Python
对Python中type打开文件的方式介绍
2018/04/28 Python
Django csrf 验证问题的实现
2018/10/09 Python
python获取微信企业号打卡数据并生成windows计划任务
2019/04/30 Python
jupyter修改文件名方式(TensorFlow)
2020/04/21 Python
三步解决python PermissionError: [WinError 5]拒绝访问的情况
2020/04/22 Python
Pandas DataFrame求差集的示例代码
2020/12/13 Python
沪江旗下的海量优质课程平台:沪江网校
2017/11/07 全球购物
来自圣地亚哥的实惠太阳镜:Knockaround
2018/08/27 全球购物
巴基斯坦购物网站:Goto
2019/03/11 全球购物
彪马荷兰官网:PUMA荷兰
2019/05/08 全球购物
SmartBuyGlasses德国:购买太阳镜和眼镜
2019/08/20 全球购物
C#里面如何判断一个Object是否是某种类型(如Boolean)?
2016/02/10 面试题
布达拉宫的导游词
2015/02/02 职场文书
python 网络编程要点总结
2021/06/18 Python
Python基础教程,Python入门教程(超详细)
2021/06/24 Python