高效编程之 concurrent.future
背景
我们知道 Python 中有多线程threading 和多进程multiprocessing 实现并发,
但是这两个东西开销很大,一是开启线程/进程的开销,二是主程序和子程序之间的通信需要 序列化和反序列化,
所以有些时候需要使用更加高级的用法,然而这些高级用法十分复杂,而且 threading 和 multiprocessing 用法还不一样。
于是诞生了 concurrent.future
1. 它可以解决大部分的复杂问题 【但并不是全部,如果尝试后效果不好,还需要使用他们的高级用法】
2. 而且统一了线程和进程的用法
concurrent.future 提供了 ThreadPoolExecutor 和 ProcessPoolExecutor 两个类,其实是对 线程池和进程池 的进一步抽象,而且具有以下特点:
3. 主程序可以获取子程序的状态和返回值
4. 子程序完成时,主程序能立刻知道
效率验证
求最大公约数,测试数据如下
def gcd(pair):
# 最大公约数
a, b = pair
low = min(a, b)
for i in range(low, 0, -1):
if a % i == 0 and b % i == 0:
return i numbers = [(1963309, 2265973), (2030677, 3814172), (1551645, 2229620), (2039045, 2020802)]
无并发
sum = 0
for i in range(20):
start = time.time()
results = list(map(gcd, numbers))
end = time.time()
sum += end - start print(sum/20) # 0.6637879729270935
多线程
from concurrent.futures import ThreadPoolExecutor
sum = 0
for i in range(20):
start = time.time()
pool = ThreadPoolExecutor(max_workers=3)
results = list(pool.map(gcd, numbers))
end = time.time()
sum += end - start print(sum/20) # 0.9184025406837464
分析:由于全局解释器锁GIL的存在,多线程无法利用多核CPU进行并行计算,而是只使用了一个核,加上本身的开销,计算效率更低了。
通过 资源管理器 查看 CPU 使用率:25%左右 【4核,用了一个】
多进程
from concurrent.futures import ProcessPoolExecutor if __name__ == '__main__':
sum = 0
for i in range(20):
start = time.time()
pool = ProcessPoolExecutor(max_workers=3)
results = list(pool.map(gcd, numbers))
end = time.time()
sum += end - start print(sum/20) # 0.8655495047569275
分析:利用多核CPU并行计算,比多线程快了点,但是由于本身的开销,还是没有无并发效率高,
通过 资源管理器 查看 CPU 使用率:75%左右 【4核,用了三个,max_workers=3】
这主要是数据量太小了,体现不出并发的优势,于是我把数据量稍微加大点
numbers = [(1963309, 2265973), (2030677, 3814172), (1551645, 2229620), (2039045, 2020802)] * 10
重新测试,无并发 7s,多进程 2s,效果明显提高。
注意,在使用多进程时,必须把 多进程代码 写在 if __name__ == '__main__' 下面,否则异常,甚至报错
concurrent.futures.process.BrokenProcessPool: A process in the process pool was terminated abruptly while the future was running or pending.
小结:多线程不适合计算密集型,适合IO密集型,后面我会验证,多进程适合计算密集型。
API 用法
具体方法参照参考资料,非常简单,这里我就不写了。
参考资料:
https://www.jianshu.com/p/b9b3d66aa0be
高效编程之 concurrent.future的更多相关文章
- Python之网络编程之concurrent.futures模块
需要注意一下不能无限的开进程,不能无限的开线程最常用的就是开进程池,开线程池.其中回调函数非常重要回调函数其实可以作为一种编程思想,谁好了谁就去掉 只要你用并发,就会有锁的问题,但是你不能一直去自己加 ...
- C++并发编程之std::future
简单地说,std::future 可以用来获取异步任务的结果,因此可以把它当成一种简单的线程间同步的手段.std::future 通常由某个 Provider 创建,你可以把 Provider 想象成 ...
- 高效编程之cache命中对于程序性能的影响
下面这个代码用两个双层循环遍历了一个二维数组里所有的元素,以我自己机器的测试 上面那个循环耗时基本为下面的一半,两个循环的时间复杂度相同,为什么会有这么大的差别? 首先要明白的是不管是几维数组,他们都 ...
- 高效编程之 cProfile 性能分析
写代码经常会听说一些名词,比如 性能分析.代码调优. cProfile 是 python 代码调优的一种工具,它能够统计在整个代码执行过程中,每个函数调用的次数和消耗的时间. 这个工具虽然很常用,但是 ...
- 并发编程之Callable异步,Future模式
Callable 在Java中,创建线程一般有两种方式,一种是继承Thread类,一种是实现Runnable接口.然而,这两种方式的缺点是在线程任务执行结束后,无法获取执行结果.我们一般只能采用共享变 ...
- Python进阶:并发编程之Futures
区分并发和并行 并发(Concurrency). 由于Python 的解释器并不是线程安全的,为了解决由此带来的 race condition 等问题,Python 便引入了全局解释器锁,也就是同一时 ...
- Python核心技术与实战——十七|Python并发编程之Futures
不论是哪一种语言,并发编程都是一项非常重要的技巧.比如我们上一章用的爬虫,就被广泛用在工业的各个领域.我们每天在各个网站.App上获取的新闻信息,很大一部分都是通过并发编程版本的爬虫获得的. 正确并合 ...
- 并发编程之:Atomic
大家好,我是小黑,一个在互联网苟且偷生的农民工. 在开始讲今天的内容之前,先问一个问题,使用int类型做加减操作是不是线程安全的呢?比如 i++ ,++i,i=i+1这样的操作在并发情况下是否会有问题 ...
- C++混合编程之idlcpp教程Python篇(6)
上一篇在这 C++混合编程之idlcpp教程Python篇(5) 第一篇在这 C++混合编程之idlcpp教程(一) 工程PythonTutorial4中加入了四个文件:PythonTutorial4 ...
随机推荐
- POJ 2195 一人一房 最小费用流 建图 水题
Going Home Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 21010 Accepted: 10614 Desc ...
- Linux服务器pxe+kickstart部署无人值守安装
一. 使用光盘镜像安装好一台Redhat6.8系统的虚拟机(图形化界面) 二. 部署相关服务程序 1. 安装并配置dhcpd服务程序 a)安装dhcp服务程序 b)对dhcp服务进 ...
- BZOJ 3456 城市规划 (组合计数、DP、FFT)
题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=3456 著名的多项式练习题,做法也很多,终于切掉了纪念 首先求一波递推式: 令\(F(n ...
- 官网Windows 10安装程序驱动下载--截止:2019.01.06版本
说明:鉴于win7,8不可直接再下载原装iOS文件,这份共享程序包是为以后N年做的准备.如果N年后这个包还可以用,就可以省去很多麻烦. 百度网盘分享:https://pan.baidu.com/s/1 ...
- vue router 报错:NavigationDuplicated {_name: "NavigationDuplicated", name: "NavigationDuplicated"}
https://blog.csdn.net/weixin_43202608/article/details/98884620
- vue中使用iconfont和在旧有的iconfont中添加新的图标
todo 使用参考:https://blog.csdn.net/qq_34802010/article/details/81451278 大体步骤是正确的,具体可参考官方文档和下载下来的代码中的dem ...
- 2.进行model和log的路径创建
第一步:使用datetime.strftime(datetime.now(), '%Y%m%d-%H%M%S') 用于生成当前时间 第二步: 使用os.path.join() 将文件的路径与subdi ...
- 【BZOJ 3709: [PA2014]Bohater】
首先,这是我n久之前培训的时候老师讲的题目了,今天突然看到,那就讲讲吧. 首先,我们考虑怎么打怪... 显然,我们需要保证这个怪要尽可能的打死(就是尽量不被干死),并且保证尽可能的净获得血量大的在前面 ...
- 洛谷P1983车站分级
洛谷\(P1983\)车站分级(拓扑排序) 目录 题目描述 题目分析 思路分析 代码实现 题目描述 题目在洛谷\(P1983\)上 题目: 一条单向的铁路线上,依次有编号为 \(1, 2, -, ...
- 浏览器端-W3School-HTML:HTML DOM cells 集合
ylbtech-浏览器端-W3School-HTML:HTML DOM cells 集合 1.返回顶部 1. HTML DOM cells 集合 HTML DOM Table 对象 定义和用法 cel ...