高效编程之 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 ...
随机推荐
- Selenium 对元素的判断(expected_conditions)(转载)
我们在用webdriver去操作元素时,先要判断这个元素是否存在,存在才去操作,否则就会报错. selenium的expected_conditions模块提供了一些判断方法 场景 Expected ...
- 工具类--BeanUtils----Bean转换工具
package com.zhouyy.netBank.util; import java.beans.PropertyDescriptor; import java.lang.reflect.Fiel ...
- Python对字典分别按键(key)和值(value)进行排序
使用sorted函数进行排序 sorted(iterable,key,reverse),sorted一共有iterable,key,reverse这三个参数;其中iterable表示可以迭代的对象,例 ...
- docker—tomcat 报错:Failed to get D-Bus connection: Operation not permitted
docker search centos 查系统镜像 docker pull docker.io/centos 进入容器 [root@git opt]# docker images REPOSIT ...
- 最近给几个CRM软件配套开发了Outlook插件,讲讲Outlook插件开发注意事项
原始出处:www.cnblogs.com/Charltsing/p/OutlookAddinsTips.html联系QQ:564955427 从去年到现在,写了四五个Outlook插件,其中两个是给C ...
- EC
- golang defer那些坑
defer以下几个特性,使用时需要关注下. 即时的参数传递 调用os.Exit()时defer不会被执行 defer与return的先后顺序 1.即时的参数传递 定义defer时传入的参数,是作为拷贝 ...
- redhat下配置SEED DVS6446开发环境1
Linux NFS服务详解 1.什么是NFS(Network FileSystem) NFS 就是 Network FileSystem 的缩写,最早之前是由 Sun 所发展出来的.他最大的 功 ...
- 【图形学手记】Inverse Transform Sampling 逆转换抽样
需求: 我们通过调查,得知大多数人在20岁左右初恋,以20岁为基准,以随机变量X表示早于或晚于该时间的年数,为了简单,假设X值域为[-5,5],并且PDF(X)是一个正态分布函数(当然可以为任意分布, ...
- HiMall 3接口鉴权参考
签名算法 为了防止API调用过程中被黑客恶意篡改,调用任何一个API都需要携带签名,HOP服务端会根据请求参数,对签名进行验证,签名不合法的请求将会被拒绝.TOP目前支持的签名算法只有一种:MD5(s ...