future初识

通过下面脚本来对future进行一个初步了解:
例子1:普通通过循环的方式

 import os
import time
import sys import requests POP20_CC = (
"CN IN US ID BR PK NG BD RU JP MX PH VN ET EG DE IR TR CD FR"
).split() BASE_URL = 'http://flupy.org/data/flags' DEST_DIR = 'downloads/' def save_flag(img,filename):
path = os.path.join(DEST_DIR,filename)
with open(path,'wb') as fp:
fp.write(img) def get_flag(cc):
url = "{}/{cc}/{cc}.gif".format(BASE_URL,cc=cc.lower())
resp = requests.get(url)
return resp.content def show(text):
print(text,end=" ")
sys.stdout.flush() def download_many(cc_list):
for cc in sorted(cc_list):
image = get_flag(cc)
show(cc)
save_flag(image,cc.lower()+".gif") return len(cc_list) def main(download_many):
t0 = time.time()
count = download_many(POP20_CC)
elapsed = time.time()-t0
msg = "\n{} flags downloaded in {:.2f}s"
print(msg.format(count,elapsed)) if __name__ == '__main__':
main(download_many)

例子2:通过future方式实现,这里对上面的部分代码进行了复用

 from concurrent import futures

 from flags import save_flag, get_flag, show, main

 MAX_WORKERS = 20

 def download_one(cc):
image = get_flag(cc)
show(cc)
save_flag(image, cc.lower()+".gif")
return cc def download_many(cc_list):
workers = min(MAX_WORKERS,len(cc_list))
with futures.ThreadPoolExecutor(workers) as executor:
res = executor.map(download_one, sorted(cc_list)) return len(list(res)) if __name__ == '__main__':
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的结果

 from concurrent import futures

 from flags import save_flag, get_flag, show, main

 MAX_WORKERS = 20

 def download_one(cc):
image = get_flag(cc)
show(cc)
save_flag(image, cc.lower()+".gif")
return cc def download_many(cc_list):
cc_list = cc_list[:5]
with futures.ThreadPoolExecutor(max_workers=3) as executor:
to_do = []
for cc in sorted(cc_list):
future = executor.submit(download_one,cc)
to_do.append(future)
msg = "Secheduled for {}:{}"
print(msg.format(cc,future)) results = []
for future in futures.as_completed(to_do):
res = future.result()
msg = "{}result:{!r}"
print(msg.format(future,res))
results.append(res) return len(results) if __name__ == '__main__':
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处理并发的更多相关文章

  1. Python 多线程教程:并发与并行

    转载于: https://my.oschina.net/leejun2005/blog/398826 在批评Python的讨论中,常常说起Python多线程是多么的难用.还有人对 global int ...

  2. python之socketserver实现并发

    python之socketserver实现并发 服务端 import socketserver #socketserver模块是用来实现并发 # 我们自己的类里一定要继承socketserver.Ba ...

  3. python 使用多进程实现并发编程/使用queue进行进程间数据交换

    import time import os import multiprocessing from multiprocessing import Queue, pool ""&qu ...

  4. python之爬虫_并发(串行、多线程、多进程、异步IO)

    并发 在编写爬虫时,性能的消耗主要在IO请求中,当单进程单线程模式下请求URL时必然会引起等待,从而使得请求整体变慢 import requests def fetch_async(url): res ...

  5. Python中实现异步并发查询数据库

    这周又填了一个以前挖下的坑. 这个博客系统使用Psycopy库实现与PostgreSQL数据库的通信.前期,只是泛泛地了解了一下SQL语言,然后就胡乱拼凑出这么一个简易博客系统. 10月份找到工作以后 ...

  6. PYTHON ASYNCIO: FUTURE, TASK AND THE EVENT LOOP

    from :http://masnun.com/2015/11/20/python-asyncio-future-task-and-the-event-loop.html Event Loop On ...

  7. python之高性能网络编程并发框架eventlet实例

    http://blog.csdn.net/mingzznet/article/details/38388299 前言: 虽然 eventlet 封装成了非常类似标准线程库的形式,但线程和eventle ...

  8. python导出zabbix数据并发邮件脚本

    Zabbix没有报表导出的功能,于是通过编写脚本导出zabbix数据并发邮件.效果如下: 下面是脚本,可根据自己的具体情况修改: #!/usr/bin/python #coding:utf-8 imp ...

  9. python使用协程并发

    协程 协程是一种用户态的轻量级线程,又称微线程. 协程拥有自己的寄存器上下文和栈,调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈.因此:协程能保留上一次调 ...

随机推荐

  1. 英语学习APP案例分析

    第一部分 调研, 评测 1.上手体验 界面简洁,有常规的词典翻译功能,针对四六级或考研的人有特别的"单词挑战"模块,以及针对口语训练的"我爱说英语"模块,多功能 ...

  2. 团队作业7——Alpha冲刺之事后诸葛亮(宣告项目失败团队解散)

    一.项目进度 1.4月5日,团队组建.满怀希望的能做好这个项目 2.4月12日,需求分析. 3.4月21日,需求改进,出现协作问题,没有做好. 4.做项目,学习新的知识,继续做项目,但是能力有限,团队 ...

  3. 201521123040《Java程序设计》第4周学习总结

    1. 本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结其他上课内容. 本周学习了类的继承,包括子类父类的概念还有extends关键字,super关键字.继承与代码 ...

  4. 201521123020《Java程序设计》第2周学习总结

    一.学习总结 学习了运算符的基本使用方法: 学习了string这个特殊的类型: 学习了数组的使用方法. 二.书面作业 1.使用Eclipse关联jdk源代码,并查看String对象的源代码(截图)? ...

  5. 201521123068 《java程序设计》 第10周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常与多线程相关内容. 2. 书面作业 本次PTA作业题集异常.多线程 1.finally 题目4-2 1.1 截图你的提交结果(出 ...

  6. 自动化测试之 seleniumIDE,Selenium1,selenium2和testNG入门

    由于前期三个月公司的项目一直在改需求阶段,一直是手动测试,现在项目雏形以及基本页面功能都确定下来,为了不让自己陷入天天测同一功能的无限循环中,故开始自动化测试的学习之路,也为自己以后的发展铺铺路. 一 ...

  7. Java实现3DES加密--及ANSI X9.8 Format标准 PIN PAN获取PIN BlOCK

    1, 采用银联ANSI X9.8标准 PIN xor PAN获取PIN BlOCK 2, 采用3Des进行加密 参考: des和3Des加密算法实现 要点:因为3DES是对称加密算法,key是24位, ...

  8. eclipse安装java ee插件方法步骤

    1.本人以前使用的MyEclipse进行Javaweb开发,但是后来由于myeclipse实在太臃肿,经常在运行的过程中不流畅 (可能电脑内存也不是太高吧)   !所以坚决换用eclipse,但是问题 ...

  9. <c:forEach>+<c:if>

    <c:forEach>:用来做循环<c:if>:相当于if语句用于判断执行,如果表达式的值为 true 则执行其主体内容. <c:forEach var="每个 ...

  10. servlet_2

    package com.atguigu.servlet; import java.io.IOException; import javax.servlet.Servlet;import javax.s ...