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 ORM框架SQLAlchemy学习笔记之映射类使用实例和Session会话介绍
Jun 10 Python
简单实现Python爬取网络图片
Apr 01 Python
Python 实现删除某路径下文件及文件夹的实例讲解
Apr 24 Python
python批量复制图片到另一个文件夹
Sep 17 Python
Python HTML解析器BeautifulSoup用法实例详解【爬虫解析器】
Apr 05 Python
python使用Qt界面以及逻辑实现方法
Jul 10 Python
Python+numpy实现矩阵的行列扩展方式
Nov 29 Python
Python random模块制作简易的四位数验证码
Feb 01 Python
Python如何实现邮件功能
May 27 Python
DataFrame.groupby()所见的各种用法详解
Jun 14 Python
Python如何截图保存的三种方法(小结)
Sep 01 Python
Python 语言实现六大查找算法
Jun 30 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调试的强悍利器之PHPDBG
2016/02/22 PHP
PHP折半(二分)查找算法实例分析
2018/05/12 PHP
firefox火狐浏览器与与ie兼容的2个问题总结
2010/07/20 Javascript
jquery聚焦文本框与扩展文本框聚焦方法
2012/10/12 Javascript
用js实现控件的隐藏及style.visibility的使用
2013/06/14 Javascript
公共js在页面底部加载的注意事项介绍
2013/07/18 Javascript
用innerhtml提高页面打开速度的方法
2013/08/02 Javascript
javascript实现table表格隔行变色的方法
2015/05/13 Javascript
使用JQuery实现的分页插件分享
2015/11/05 Javascript
基于JavaScript实现简单的随机抽奖小程序
2016/01/05 Javascript
BootStrap实用代码片段之一
2016/03/22 Javascript
利用jquery禁止外层滚动条的滚动
2017/01/05 Javascript
jquery实现侧边栏左右伸缩效果的示例
2017/12/19 jQuery
Vue.set()实现数据动态响应的方法
2018/02/07 Javascript
JS实现为动态创建的元素添加事件操作示例
2018/03/17 Javascript
详解如何使用微信小程序云函数发送短信验证码
2019/03/13 Javascript
node.js ws模块搭建websocket服务端的方法示例
2019/04/25 Javascript
vuex刷新后数据丢失的解决方法
2020/10/18 Javascript
vue+iview实现分页及查询功能
2020/11/17 Vue.js
ES2020让代码更优美的运算符 (?.) (??)
2021/01/04 Javascript
[02:57]DOTA2亚洲邀请赛小组赛第四日 赛事回顾
2015/02/02 DOTA
python小技巧之批量抓取美女图片
2014/06/06 Python
Python文本统计功能之西游记用字统计操作示例
2018/05/07 Python
Python BeautifulSoup [解决方法] TypeError: list indices must be integers or slices, not str
2019/08/07 Python
Django实现简单网页弹出警告代码
2019/11/15 Python
基于Python把网站域名解析成ip地址
2020/05/25 Python
pytorch中的weight-initilzation用法
2020/06/24 Python
JBL美国官方商店:扬声器、耳机等
2019/12/01 全球购物
学前教育毕业生自荐信范文
2013/12/24 职场文书
护士长竞聘书
2014/03/31 职场文书
项目安全员岗位职责
2015/02/15 职场文书
自主招生专家推荐信
2015/03/26 职场文书
关于召开会议的通知
2015/04/15 职场文书
小学教师师德师风承诺书
2015/04/28 职场文书
python 实现德洛内三角剖分的操作
2021/04/22 Python
SONY600GR,国产收音机厂商永远的痛
2022/04/05 无线电