背景

我们知道 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. BZOJ 4386 Luogu P3597 [POI2015]Wycieczki (矩阵乘法)

    题目链接: (bzoj) https://www.lydsy.com/JudgeOnline/problem.php?id=4386 (luogu) https://www.luogu.org/pro ...

  2. CodeForces 788B--Weird journey

    Time Limit:2000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Description Little ...

  3. [笔记]mongodb一

    一.MongoDB介绍 MongoDB是一个由c++编写的基于分布式文件存储的数据库.MongoDB介于关系型数据库和非关系型数据库之间,是非关系型数据库中功能最丰富,最接近关系型数据库.具有高性能, ...

  4. linux 中的 "2>&1"含义

    文章摘自:http://os.chinaunix.net/a2009/0903/996/000000996941.shtml 脚本是: nohup /mnt/Nand3/H2000G >/dev ...

  5. linux 文件目录介绍

    网上的资源 太多了,copy 过来 留给自己用吧! 摘自 : http:/ 使用linux也有一年多时间了  最近也是一直在维护网站系统主机  下面是linux目录结构说明 本人使用的是centos系 ...

  6. SQL Server清空数据库中ldf日志文件

    USE [master] ALTER DATABASE [Whir_InternalSystem] SET RECOVERY SIMPLE WITH NO_WAIT ALTER DATABASE [W ...

  7. laravel 浏览器图标的设置方式

    <head> <meta charset="UTF-8"> <title>叮叮书店</title> <link href=&q ...

  8. C# hook WndProc

    在当前窗口里重载WndProc,只能捕获到当前WinForm窗口的消息 protected override void WndProc(ref Message m) { if (m.Msg == WM ...

  9. python 实验2 分支结构

    该博客专为我的小伙伴们提供参考而附加,没空加上代码具体解析,望各位谅解 实验一   货币转换   ‪‪‪‪‪‫‪‪‪‪‪写一个程序进行人民币和欧元间币值转换,其中:‪‪‪‪‪‫‪‪‪‪‪‫‪‪‪‪‪‫ ...

  10. java 接口default的判断规则

    1.前言 jdk1.8中新增加了default关键字,就是在接口中可以增加默认实现. 因为改动接口所有的实现类都要改动,所以增加了default关键字后不需要修改其他类,默认给所有实现类增加了方法. ...