背景

我们知道 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的更多相关文章

  1. Python之网络编程之concurrent.futures模块

    需要注意一下不能无限的开进程,不能无限的开线程最常用的就是开进程池,开线程池.其中回调函数非常重要回调函数其实可以作为一种编程思想,谁好了谁就去掉 只要你用并发,就会有锁的问题,但是你不能一直去自己加 ...

  2. C++并发编程之std::future

    简单地说,std::future 可以用来获取异步任务的结果,因此可以把它当成一种简单的线程间同步的手段.std::future 通常由某个 Provider 创建,你可以把 Provider 想象成 ...

  3. 高效编程之cache命中对于程序性能的影响

    下面这个代码用两个双层循环遍历了一个二维数组里所有的元素,以我自己机器的测试 上面那个循环耗时基本为下面的一半,两个循环的时间复杂度相同,为什么会有这么大的差别? 首先要明白的是不管是几维数组,他们都 ...

  4. 高效编程之 cProfile 性能分析

    写代码经常会听说一些名词,比如 性能分析.代码调优. cProfile 是 python 代码调优的一种工具,它能够统计在整个代码执行过程中,每个函数调用的次数和消耗的时间. 这个工具虽然很常用,但是 ...

  5. 并发编程之Callable异步,Future模式

    Callable 在Java中,创建线程一般有两种方式,一种是继承Thread类,一种是实现Runnable接口.然而,这两种方式的缺点是在线程任务执行结束后,无法获取执行结果.我们一般只能采用共享变 ...

  6. Python进阶:并发编程之Futures

    区分并发和并行 并发(Concurrency). 由于Python 的解释器并不是线程安全的,为了解决由此带来的 race condition 等问题,Python 便引入了全局解释器锁,也就是同一时 ...

  7. Python核心技术与实战——十七|Python并发编程之Futures

    不论是哪一种语言,并发编程都是一项非常重要的技巧.比如我们上一章用的爬虫,就被广泛用在工业的各个领域.我们每天在各个网站.App上获取的新闻信息,很大一部分都是通过并发编程版本的爬虫获得的. 正确并合 ...

  8. 并发编程之:Atomic

    大家好,我是小黑,一个在互联网苟且偷生的农民工. 在开始讲今天的内容之前,先问一个问题,使用int类型做加减操作是不是线程安全的呢?比如 i++ ,++i,i=i+1这样的操作在并发情况下是否会有问题 ...

  9. C++混合编程之idlcpp教程Python篇(6)

    上一篇在这 C++混合编程之idlcpp教程Python篇(5) 第一篇在这 C++混合编程之idlcpp教程(一) 工程PythonTutorial4中加入了四个文件:PythonTutorial4 ...

随机推荐

  1. POJ 2195 一人一房 最小费用流 建图 水题

    Going Home Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 21010   Accepted: 10614 Desc ...

  2. Linux服务器pxe+kickstart部署无人值守安装

    一.    使用光盘镜像安装好一台Redhat6.8系统的虚拟机(图形化界面) 二.    部署相关服务程序 1.     安装并配置dhcpd服务程序 a)安装dhcp服务程序 b)对dhcp服务进 ...

  3. BZOJ 3456 城市规划 (组合计数、DP、FFT)

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=3456 著名的多项式练习题,做法也很多,终于切掉了纪念 首先求一波递推式: 令\(F(n ...

  4. 官网Windows 10安装程序驱动下载--截止:2019.01.06版本

    说明:鉴于win7,8不可直接再下载原装iOS文件,这份共享程序包是为以后N年做的准备.如果N年后这个包还可以用,就可以省去很多麻烦. 百度网盘分享:https://pan.baidu.com/s/1 ...

  5. vue router 报错:NavigationDuplicated {_name: "NavigationDuplicated", name: "NavigationDuplicated"}

    https://blog.csdn.net/weixin_43202608/article/details/98884620

  6. vue中使用iconfont和在旧有的iconfont中添加新的图标

    todo 使用参考:https://blog.csdn.net/qq_34802010/article/details/81451278 大体步骤是正确的,具体可参考官方文档和下载下来的代码中的dem ...

  7. 2.进行model和log的路径创建

    第一步:使用datetime.strftime(datetime.now(), '%Y%m%d-%H%M%S') 用于生成当前时间 第二步: 使用os.path.join() 将文件的路径与subdi ...

  8. 【BZOJ 3709: [PA2014]Bohater】

    首先,这是我n久之前培训的时候老师讲的题目了,今天突然看到,那就讲讲吧. 首先,我们考虑怎么打怪... 显然,我们需要保证这个怪要尽可能的打死(就是尽量不被干死),并且保证尽可能的净获得血量大的在前面 ...

  9. 洛谷P1983车站分级

    洛谷\(P1983\)车站分级(拓扑排序) 目录 题目描述 题目分析 思路分析 代码实现 题目描述 题目在洛谷\(P1983\)上 ​ 题目: 一条单向的铁路线上,依次有编号为 \(1, 2, -, ...

  10. 浏览器端-W3School-HTML:HTML DOM cells 集合

    ylbtech-浏览器端-W3School-HTML:HTML DOM cells 集合 1.返回顶部 1. HTML DOM cells 集合 HTML DOM Table 对象 定义和用法 cel ...