Python通过future处理并发
future初识
通过下面脚本来对future进行一个初步了解:
例子1:普通通过循环的方式
1 import os 2 import time 3 import sys 4 5 import requests 6 7 8 POP20_CC = ( 9 "CN IN US ID BR PK NG BD RU JP MX PH VN ET EG DE IR TR CD FR" 10 ).split() 11 12 13 BASE_URL = 'http://flupy.org/data/flags' 14 15 DEST_DIR = 'downloads/' 16 17 18 def save_flag(img,filename): 19 path = os.path.join(DEST_DIR,filename) 20 with open(path,'wb') as fp: 21 fp.write(img) 22 23 24 def get_flag(cc): 25 url = "{}/{cc}/{cc}.gif".format(BASE_URL,cc=cc.lower()) 26 resp = requests.get(url) 27 return resp.content 28 29 30 def show(text): 31 print(text,end=" ") 32 sys.stdout.flush() 33 34 35 def download_many(cc_list): 36 for cc in sorted(cc_list): 37 image = get_flag(cc) 38 show(cc) 39 save_flag(image,cc.lower()+".gif") 40 41 return len(cc_list) 42 43 44 def main(download_many): 45 t0 = time.time() 46 count = download_many(POP20_CC) 47 elapsed = time.time()-t0 48 msg = "\n{} flags downloaded in {:.2f}s" 49 print(msg.format(count,elapsed)) 50 51 52 if __name__ == '__main__': 53 main(download_many)
例子2:通过future方式实现,这里对上面的部分代码进行了复用
1 from concurrent import futures 2 3 from flags import save_flag, get_flag, show, main 4 5 6 MAX_WORKERS = 20 7 8 9 def download_one(cc): 10 image = get_flag(cc) 11 show(cc) 12 save_flag(image, cc.lower()+".gif") 13 return cc 14 15 16 def download_many(cc_list): 17 workers = min(MAX_WORKERS,len(cc_list)) 18 with futures.ThreadPoolExecutor(workers) as executor: 19 res = executor.map(download_one, sorted(cc_list)) 20 21 return len(list(res)) 22 23 24 if __name__ == '__main__': 25 main(download_many)
分别运行三次,两者的平均速度:13.67和1.59s,可以看到差别还是非常大的。
future
future是concurrent.futures模块和asyncio模块的重要组件
从python3.4开始标准库中有两个名为Future的类:concurrent.futures.Future和asyncio.Future
这两个类的作用相同:两个Future类的实例都表示可能完成或者尚未完成的延迟计算。与Twisted中的Deferred类、Tornado框架中的Future类的功能类似
注意:通常情况下自己不应该创建future,而是由并发框架(concurrent.futures或asyncio)实例化
原因:future表示终将发生的事情,而确定某件事情会发生的唯一方式是执行的时间已经安排好,因此只有把某件事情交给concurrent.futures.Executor子类处理时,才会创建concurrent.futures.Future实例。
如:Executor.submit()方法的参数是一个可调用的对象,调用这个方法后会为传入的可调用对象排定时间,并返回一个future
客户端代码不能应该改变future的状态,并发框架在future表示的延迟计算结束后会改变期物的状态,我们无法控制计算何时结束。
这两种future都有.done()方法,这个方法不阻塞,返回值是布尔值,指明future链接的可调用对象是否已经执行。客户端代码通常不会询问future是否运行结束,而是会等待通知。因此两个Future类都有.add_done_callback()方法,这个方法只有一个参数,类型是可调用的对象,future运行结束后会调用指定的可调用对象。
.result()方法是在两个Future类中的作用相同:返回可调用对象的结果,或者重新抛出执行可调用的对象时抛出的异常。但是如果future没有运行结束,result方法在两个Futrue类中的行为差别非常大。
对concurrent.futures.Future实例来说,调用.result()方法会阻塞调用方所在的线程,直到有结果可返回,此时,result方法可以接收可选的timeout参数,如果在指定的时间内future没有运行完毕,会抛出TimeoutError异常。
而asyncio.Future.result方法不支持设定超时时间,在获取future结果最好使用yield from结构,但是concurrent.futures.Future不能这样做
不管是asyncio还是concurrent.futures.Future都会有几个函数是返回future,其他函数则是使用future,在最开始的例子中我们使用的Executor.map就是在使用future,返回值是一个迭代器,迭代器的__next__方法调用各个future的result方法,因此我们得到的是各个futrue的结果,而不是future本身
关于future.as_completed函数的使用,这里我们用了两个循环,一个用于创建并排定future,另外一个用于获取future的结果
1 from concurrent import futures 2 3 from flags import save_flag, get_flag, show, main 4 5 6 MAX_WORKERS = 20 7 8 9 def download_one(cc): 10 image = get_flag(cc) 11 show(cc) 12 save_flag(image, cc.lower()+".gif") 13 return cc 14 15 16 def download_many(cc_list): 17 cc_list = cc_list[:5] 18 with futures.ThreadPoolExecutor(max_workers=3) as executor: 19 to_do = [] 20 for cc in sorted(cc_list): 21 future = executor.submit(download_one,cc) 22 to_do.append(future) 23 msg = "Secheduled for {}:{}" 24 print(msg.format(cc,future)) 25 26 results = [] 27 for future in futures.as_completed(to_do): 28 res = future.result() 29 msg = "{}result:{!r}" 30 print(msg.format(future,res)) 31 results.append(res) 32 33 return len(results) 34 35 36 if __name__ == '__main__': 37 main(download_many)
结果如下:
注意:Python代码是无法控制GIL,标准库中所有执行阻塞型IO操作的函数,在等待操作系统返回结果时都会释放GIL.运行其他线程执行,也正是因为这样,Python线程可以在IO密集型应用中发挥作用
以上都是concurrent.futures启动线程,下面通过它启动进程
concurrent.futures启动进程
concurrent.futures中的ProcessPoolExecutor类把工作分配给多个Python进程处理,因此,如果需要做CPU密集型处理,使用这个模块能绕开GIL,利用所有的CPU核心。
其原理是一个ProcessPoolExecutor创建了N个独立的Python解释器,N是系统上面可用的CPU核数。
使用方法和ThreadPoolExecutor方法一样
所有的努力都值得期许,每一份梦想都应该灌溉!
Python通过future处理并发相关推荐
- 读书笔记:《流畅的Python》第17章 使用future处理并发
# 第17章 使用future处理并发""" 内容提要:concurrent.futures模块future的概念:是一种对象,表示异步执行的操作是concurrent. ...
- Python concurrent.future 使用教程及源码初剖
前言 原文发在这里的 Python concurrent.future 使用教程及源码初剖 垃圾话 很久没写博客了,想了想不能再划水,于是给自己定了一个目标,写点 concurrent.future ...
- python实现摄像头拍照_使用Python控制摄像头拍照并发邮件
o1 前言 为什么会有写这个程序的想法呢? 最初的想法是写一个可以用电脑前置摄像头拍照的程序,在舍友使用你电脑的时候,不经意间获取到一大堆奇葩舍友的表情包. 然后我又突发奇想,要不搞个开机启动吧,这样 ...
- python之socketserver实现并发
python之socketserver实现并发 服务端 import socketserver #socketserver模块是用来实现并发 # 我们自己的类里一定要继承socketserver.Ba ...
- python并发循环_在Python中模拟一个并发循环?
在Python中模拟一个并发循环? 我需要模拟Python程序中的并发循环.不幸的是,以下简单的代码不起作用:list_of_ints = [ 1, 2, 3 ]iterator = list_of_ ...
- python go高并发_天下武功为快不破,戏说Python与Go高并发争锋!
在这个以斗气大陆横行的世界,每一个大的势力宗门都有自己的杀手锏的功法,比如老牌的古族有C++这样的巨无霸语言,药族有C语言,几乎斗气大陆所有的操作系统都是用C语言做的,毕竟斗气都要靠吃丹药维持.而实力 ...
- 天下武功为快不破,戏说Python与Go高并发争锋!
在这个以斗气大陆横行的世界,每一个大的势力宗门都有自己的杀手锏的功法,比如老牌的古族有C++这样的巨无霸语言,药族有C语言,几乎斗气大陆所有的操作系统都是用C语言做的,毕竟斗气都要靠吃丹药维持.而实力 ...
- Python学习之路36-使用future处理并发
<流畅的Python>笔记. 本篇主要讨论concurrent.futures模块,并用它实现一个简单的并发操作. 1. 前言 我们都知道,如果有大量数据要处理,或者要处理大量链接,异步操 ...
- 桐花万里python路-高级篇-并发编程-03-线程
理论 进程只是一个资源单位,线程才是cpu上的执行单位 无需申请空间,创建开销小 共享和创建开销 多线程共享一个进程的地址空间 线程比进程更轻量级,线程比进程更容易创建可撤销 I/O密集型,多线程,会 ...
最新文章
- SpringBoot笔记:SpringBoot2.3集成Logback日志组件配置
- go读取excel_Excelize 2.3.0 发布,Go 语言 Excel 文档基础库
- 使用网真和WAD热部署Kubernetes
- 洛谷 P3367 【模板】并查集
- 如何保证投票公平_从声音玩具淘汰、五条人复活,我看到了《乐队的夏天》的不公平...
- java酒店信息管理系统_java实现酒店管理系统
- “哎哟,真的很快哦” 闪送宣布签约周杰伦为其品牌代言人
- 测试计划与测试方案的区别
- java接收jsonarray_java-如何通过JSONArray获取API的数据
- Android逆向系列之ARM语法篇
- linux第八周实验
- ddm模型公式_绝对估值法DDM、DCF模型和RNAV简介
- 《暗时间》读书笔记与读后感
- 51单片机按键控制数码管0~9_LED数码管精选电路方案合辑
- Polarr Photo教程:如何为照片增加云雾效果
- Python爬虫简单运用爬取代理IP
- jqGrid 学习笔记整理——基础篇
- 需求工程的“拨乱反正”
- 二进制#逻辑计算#与(∧)、或(∨)、非(¬)、异或(⨁)#与,或,非,异或的运算法则#与,或,非,异或运算的基础代码
- vasp结构优化英语_活动 | 英语学院举办研究生招生线上宣讲会