背景

我们知道 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. Hedera: Dynamic Flow Scheduling for Data Center Networks

    摘要: 当今的数据中心为成千上万台计算机的群集提供了巨大的聚合带宽, 但是即使在最高端的交换机中,端口密度也受到限制,因此数据中心拓扑通常由多根树组成,这些树在任何给定的主机对之间都具有许多等价路径. ...

  2. fastdfs 中client.conf 文件

    # connect timeout in seconds# default value is 30sconnect_timeout=30              连接超时 # network tim ...

  3. ship(动态规划)

    (ships.pas/c/cpp) 来源:<奥赛经典>(提高篇)[问题描述]PALMIA国家被一条河流分成南北两岸, 南北两岸上各有N个村庄. 北岸的每一个村庄有一个唯一的朋友在南岸,且他 ...

  4. nginx负载均衡 之集群概念与负载均衡

    集群介绍 为什么要用集群

  5. python 生成随机数的几种方法

      随机取一个: import random random.choice(string.digits)#从数字里随机选取一位数字: 随机取多位数:   random.sample(string.dig ...

  6. vue一些注意事项

    1.生命周期钩子的 this 上下文指向调用它的 Vue 实例. 不要在选项属性或回调上使用箭头函数,比如 created: () => console.log(this.a) 或 vm.$wa ...

  7. linux 实现U盘自动挂载

    某些场景下,服务器可能没有必要的键盘等输入设备.屏幕等输出设备.此时需要在没有人为干预的情况下实现当插入U盘或者硬盘后自动挂载,并执行某些脚本动作.以下是我的实践过程. 必要组件 udev,udisk ...

  8. Singletom 单例

    class Singletom { //最差写法.构造方法是public的,有可能会被new出多个,那就不是单例了. public Singletom(){ } public static Singl ...

  9. RESTE MASTER和reset slave

    RESET MASTER 删除所有index file 中记录的所有binlog 文件,将日志索引文件清空,创建一个新的日志文件,这个命令通常仅仅用于第一次用于搭建主从关系的时的主库, 注意   re ...

  10. react native props上存在的属性,显示不存在

    问题:类型“Readonly<{}> & Readonly<{ children?: ReactNode; }>”上不存在属性“navigation”.ts(2339) ...