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 相关文章推荐
django 自定义用户user模型的三种方法
Nov 18 Python
python通过openpyxl生成Excel文件的方法
May 12 Python
Python从MP3文件获取id3的方法
Jun 15 Python
Python回调函数用法实例详解
Jul 02 Python
Python的爬虫程序编写框架Scrapy入门学习教程
Jul 02 Python
ubuntu中配置pyqt4环境教程
Dec 27 Python
Python基于csv模块实现读取与写入csv数据的方法
Jan 18 Python
python中调试或排错的五种方法示例
Sep 12 Python
Python爬虫爬取博客实现可视化过程解析
Jun 29 Python
解决python3中os.popen()出错的问题
Nov 19 Python
在python3.9下如何安装scrapy的方法
Feb 03 Python
python实现图片转字符画
Feb 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
Win2003服务器安全加固设置--进一步提高服务器安全性
2007/05/23 PHP
php获取表单中多个同名input元素的值
2014/03/20 PHP
PHP cookie与session会话基本用法实例分析
2019/11/18 PHP
JavaScript 异步调用框架 (Part 2 - 用例设计)
2009/08/03 Javascript
用jquery与css打造个性化的单选框和复选框
2010/10/20 Javascript
js中使用DOM复制(克隆)指定节点名数据到新的XML文件中的代码
2011/07/27 Javascript
JS定时刷新页面及跳转页面的方法
2013/07/04 Javascript
JavaScript函数获取事件源的小例子
2014/05/14 Javascript
推荐25个超炫的jQuery网格插件
2014/11/28 Javascript
JavaScript实现三阶幻方算法谜题解答
2014/12/29 Javascript
jquery实现简单的无缝滚动
2015/04/15 Javascript
javascript判断变量是否有值的方法
2015/04/20 Javascript
jquery图片滚动放大代码分享(2)
2015/08/28 Javascript
JS实现三个层重叠点击互相切换的方法
2015/10/06 Javascript
基于jquery插件编写countdown计时器
2016/06/12 Javascript
Bootstrap使用基础教程详解
2016/09/05 Javascript
JQuery实现DIV其他动画效果的简单实例
2016/09/18 Javascript
如何使用less实现随机下雪动画详解
2019/01/02 Javascript
浅谈Webpack多页应用HMR卡住问题
2019/04/24 Javascript
js实现开关灯效果
2020/03/30 Javascript
9种方法优化jQuery代码详解
2020/02/04 jQuery
python常规方法实现数组的全排列
2015/03/17 Python
Python入门Anaconda和Pycharm的安装和配置详解
2019/07/16 Python
python getpass模块用法及实例详解
2019/10/07 Python
基于python3监控服务器状态进行邮件报警
2019/10/19 Python
python内打印变量之%和f的实例
2020/02/19 Python
pycharm如何使用anaconda中的各种包(操作步骤)
2020/07/31 Python
python 两种方法修改文件的创建时间、修改时间、访问时间
2020/09/26 Python
浅谈CSS3 box-sizing 属性 有趣的盒模型
2019/04/02 HTML / CSS
全球领先美式家具品牌:Ashley爱室丽家居
2017/08/07 全球购物
Python面试题集
2012/03/08 面试题
医药工作者的求职信范文
2013/09/21 职场文书
领导视察欢迎词
2014/01/15 职场文书
政风行风评议个人心得体会
2014/10/29 职场文书
初中军训感言
2015/08/01 职场文书
alibaba seata服务端具体实现
2022/02/24 Java/Android