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检测远程服务器tcp端口的方法
Mar 14 Python
python中的装饰器详解
Apr 13 Python
Python下载指定页面上图片的方法
May 12 Python
python3+django2开发一个简单的人员管理系统过程详解
Jul 23 Python
python利用itertools生成密码字典并多线程撞库破解rar密码
Aug 12 Python
下载与当前Chrome对应的chromedriver.exe(用于python+selenium)
Jan 14 Python
Python常用库大全及简要说明
Jan 17 Python
Python pip install如何修改默认下载路径
Apr 29 Python
基于python实现破解滑动验证码过程解析
May 28 Python
Python 存取npy格式数据实例
Jul 01 Python
python中entry用法讲解
Dec 04 Python
Django 实现图片上传和下载功能
Dec 31 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
可快速识别放射性物质-国外大神教你diy一个开放式辐射探测器
2020/03/12 无线电
PHP中explode函数和split函数的区别小结
2016/08/24 PHP
各情景下元素宽高的获取实现代码
2011/09/13 Javascript
JavaScript 操作table,可以新增行和列并且隔一行换背景色代码分享
2013/07/05 Javascript
Javascript基础教程之定义和调用函数
2015/01/18 Javascript
JS实现的生成随机数的4个函数分享
2015/02/11 Javascript
js实现简单的可切换选项卡效果
2015/04/10 Javascript
基于canvas实现的绚丽圆圈效果完整实例
2016/01/26 Javascript
js实现目录链接,内容跟着目录滚动显示的简单实例
2016/10/15 Javascript
微信小程序 详解页面跳转与返回并回传数据
2017/02/13 Javascript
nodejs构建本地web测试服务器 如何解决访问静态资源问题
2017/07/14 NodeJs
简单快速的实现js计算器功能
2017/08/17 Javascript
深入浅析ES6 Class 中的 super 关键字
2017/10/20 Javascript
nuxt中使用路由守卫的方法步骤
2019/01/27 Javascript
js字符串类型String常用操作实例总结
2019/07/05 Javascript
用JS实现选项卡
2020/03/23 Javascript
谈谈JavaScript中的函数
2020/09/08 Javascript
[01:02:25]2014 DOTA2华西杯精英邀请赛 5 24 iG VS DK
2014/05/26 DOTA
对于Python的Django框架部署的一些建议
2015/04/09 Python
学习python 之编写简单乘法运算题
2016/02/27 Python
python中yaml配置文件模块的使用详解
2018/04/27 Python
基于Python开发chrome插件的方法分析
2018/07/07 Python
Python实现常见的回文字符串算法
2018/11/14 Python
Python中psutil的介绍与用法
2019/05/02 Python
python 利用pyttsx3文字转语音过程详解
2019/09/25 Python
python 字典的打印实现
2019/09/26 Python
使用css3实现的tab选项卡代码分享
2014/12/09 HTML / CSS
用CSS3的box-reflect来制作倒影效果
2016/11/15 HTML / CSS
英国在线玫瑰专家:InterRose
2019/12/01 全球购物
毕业生的自我鉴定
2013/10/29 职场文书
拓展培训心得体会
2014/01/04 职场文书
教师师德反思材料
2014/02/15 职场文书
英文升职感谢信
2015/01/23 职场文书
手残删除python之后的补救方法
2021/06/26 Python
Javascript 解构赋值详情
2021/11/17 Javascript
在Docker容器中部署SQL Server
2022/04/11 Servers