Python标准模块--concurrent.futures
1 模块简介
concurrent.futures模块是在Python3.2中添加的。根据Python的官方文档,concurrent.futures模块提供给开发者一个执行异步调用的高级接口。concurrent.futures基本上就是在Python的threading和multiprocessing模块之上构建的抽象层,更易于使用。尽管这个抽象层简化了这些模块的使用,但是也降低了很多灵活性,所以如果你需要处理一些定制化的任务,concurrent.futures或许并不适合你。
concurrent.futures包括抽象类Executor,它并不能直接被使用,所以你需要使用它的两个子类:ThreadPoolExecutor或者ProcessPoolExecutor。正如你所猜的,这两个子类分别对应着Python的threading和multiprocessing接口。这两个子类都提供了池,你可以将线程或者进程放入其中。
在计算机科学中,future有着特殊的含义。当使用concurrent技术时,它可以被用于同步操作。future也可以描述在任务结束之前,进程或者线程的结果。我喜欢将它看作即将发生的结果。
2 模块使用
2.1 创建池
你可以通过concurrent.futures很容易地创建一个工作池。实例如下,
import os
import urllib.request
from concurrent.futures import ThreadPoolExecutor
from concurrent.futures import as_completed
def downloader(url):
req = urllib.request.urlopen(url)
filename = os.path.basename(url)
ext = os.path.splitext(url)[1]
if not ext:
raise RuntimeError("URL does not contain an extension")
with open(filename,"wb") as file_handle:
while True:
chunk = req.read(1024)
if not chunk:
break
file_handle.write(chunk)
msg = "Finished downloading {filename}".format(filename = filename)
return msg
def main(urls):
with ThreadPoolExecutor(max_workers = 5) as executor:
futures = [executor.submit(downloader,url) for url in urls]
for future in as_completed(futures):
print(future.result())
if __name__ == "__main__":
urls = ["http://www.irs.gov/pub/irs-pdf/f1040.pdf",
"http://www.irs.gov/pub/irs-pdf/f1040a.pdf",
"http://www.irs.gov/pub/irs-pdf/f1040ez.pdf",
"http://www.irs.gov/pub/irs-pdf/f1040es.pdf",
"http://www.irs.gov/pub/irs-pdf/f1040sb.pdf"]
main(urls)
首先,我们引入我们需要的模块。然后,我们创建downloader函数,会检查URL是否有扩展名,如果没有扩展名,我们就会抛出RuntimeError错误。然后,我们创建main函数,在这里,我们会实例化一个线程池。你可以在ThreadPoolExecutor和ProcessPoolExecutor上使用Python的with语句。
我们设置线程池中工作线程数目为5。然后我们通过列表创建一组futures(或者为任务),最后,我们调用as_complete函数。这个函数是一个迭代器,当任务结束时,会返回任务。当它们完成时,我们将结果打印出来,结果就是我们的downloader函数返回的一个字符串。
如果我们使用的函数是计算密集型的,我们可以使用ProcessPoolExecutor,替代ThreadPoolExecutor,仅仅需要修改一行代码。
我们可以使用concurrent.futures中的map方法,让代码更加简洁。让我们将上述代码重构一下,如下所示,
import os
import urllib.request
from concurrent.futures import ThreadPoolExecutor
from concurrent.futures import as_completed
def downloader(url):
req = urllib.request.urlopen(url)
filename = os.path.basename(url)
ext = os.path.splitext(url)[1]
if not ext:
raise RuntimeError("URL does not contain an extension")
with open(filename,"wb") as file_handle:
while True:
chunk = req.read(1024)
if not chunk:
break
file_handle.write(chunk)
msg = "Finished downloading {filename}".format(filename = filename)
return msg
def main(urls):
with ThreadPoolExecutor(max_workers = 5) as executor:
return executor.map(downloader, urls ,timeout = 60)
if __name__ == "__main__":
urls = ["http://www.irs.gov/pub/irs-pdf/f1040.pdf",
"http://www.irs.gov/pub/irs-pdf/f1040a.pdf",
"http://www.irs.gov/pub/irs-pdf/f1040ez.pdf",
"http://www.irs.gov/pub/irs-pdf/f1040es.pdf",
"http://www.irs.gov/pub/irs-pdf/f1040sb.pdf"]
results = main(urls)
for result in results:
print(result)
主要的区别在main函数中,已经被减少到两行代码。concurrent.futures中的map方法类似于Python中的map方法,它获取一个函数和一个可迭代对象,然后在可迭代对象上每个元素上依次调用这个函数。你也可以在你的每个线程中加入timeout,如果某一个线程挂掉,整个程序就会停止。最后,在Python3.5中,他们添加了chunksize变量,在很大的可迭代对象上使用线程池,可以改善性能。如果你使用的进程池,chunksize不会起作用。
2.2 死锁
concurrent.futures模块有一个缺陷,当调用一个关联任务,这个任务又在等待另一个任务时,你就会进入死锁。这个听起来很令人困惑,让我们看一个实例,
from concurrent.futures import ThreadPoolExecutor
def wait_forever():
my_future = executor.submit(zip,[1,2,3],[4,5,6])
result = my_future.result()
print(result)
if __name__ == "__main__":
executor = ThreadPoolExecutor(max_workers = 1)
executor.submit(wait_forever)
首先,我们引入ThreadPoolExecutor类,并实例化它。需要注意的是,我们设置最大的工作进程数目为1。然后,我们注册wait_forever函数。在wait_forever函数中,我们向线程池中注册了另一个任务--将两个列表打包在一起,获得这个操作的结果,并将结果打印出出来。但是,我们却创建了一个死锁。原因就是我们有一个任务等待另一个任务结束,也就是我们希望一个未完成的操作去等待另一个未完成的无效操作。
让我们将它重写,如下所示,
from concurrent.futures import ThreadPoolExecutor
def wait_forever():
my_future = executor.submit(zip,[1,2,3],[4,5,6])
return my_future
if __name__ == "__main__":
executor = ThreadPoolExecutor(max_workers = 3)
fut = executor.submit(wait_forever)
result = fut.result()
print(list(result.result()))
在这里,我们仅仅返回函数内部的任务,然后获取它的结果。在我们返回的任务上调用result()方法的结果就会包含我们想要的结果,看起来似乎有些令人困惑。无论如何,如果我们在这个任务上调用result()方法,我们就会获得一个打包的对象,为了了解实际的结果就是是什么,我们使用Python的list函数将打包对象进行包裹,然后打印出来。
3 Reference
Python标准模块--concurrent.futures的更多相关文章
- Thread类的其他方法,同步锁,死锁与递归锁,信号量,事件,条件,定时器,队列,Python标准模块--concurrent.futures
参考博客: https://www.cnblogs.com/xiao987334176/p/9046028.html 线程简述 什么是线程?线程是cpu调度的最小单位进程是资源分配的最小单位 进程和线 ...
- python 全栈开发,Day42(Thread类的其他方法,同步锁,死锁与递归锁,信号量,事件,条件,定时器,队列,Python标准模块--concurrent.futures)
昨日内容回顾 线程什么是线程?线程是cpu调度的最小单位进程是资源分配的最小单位 进程和线程是什么关系? 线程是在进程中的 一个执行单位 多进程 本质上开启的这个进程里就有一个线程 多线程 单纯的在当 ...
- python全栈开发,Day42(Thread类的其他方法,同步锁,死锁与递归锁,信号量,事件,条件,定时器,队列,Python标准模块--concurrent.futures)
昨日内容回顾 线程 什么是线程? 线程是cpu调度的最小单位 进程是资源分配的最小单位 进程和线程是什么关系? 线程是在进程中的一个执行单位 多进程 本质上开启的这个进程里就有一个线程 多线程 单纯的 ...
- Python标准模块--concurrent.futures(进程池,线程池)
python为我们提供的标准模块concurrent.futures里面有ThreadPoolExecutor(线程池)和ProcessPoolExecutor(进程池)两个模块. 在这个模块里他们俩 ...
- Python标准模块--concurrent.futures 进程池线程池终极用法
concurrent.futures 这个模块是异步调用的机制concurrent.futures 提交任务都是用submitfor + submit 多个任务的提交shutdown 是等效于Pool ...
- Python--day41--线程池--python标准模块concurrent.futures
1,线程池代码示例:(注:进程池的话只要将以下代码中的ThreadPoolExecutor替换成ProcessPoolExecutor即可,这里不演示) import time from concur ...
- Python标准模块--threading
1 模块简介 threading模块在Python1.5.2中首次引入,是低级thread模块的一个增强版.threading模块让线程使用起来更加容易,允许程序同一时间运行多个操作. 不过请注意,P ...
- Python标准模块--logging
1 logging模块简介 logging模块是Python内置的标准模块,主要用于输出运行日志,可以设置输出日志的等级.日志保存路径.日志文件回滚等:相比print,具备如下优点: 可以通过设置不同 ...
- Python标准模块--importlib
作者:zhbzz2007 出处:http://www.cnblogs.com/zhbzz2007 欢迎转载,也请保留这段声明.谢谢! 1 模块简介 Python提供了importlib包作为标准库的一 ...
随机推荐
- nodejs进阶(5)—接收请求参数
1. get请求参数接收 我们简单举一个需要接收参数的例子 如果有个查找功能,查找关键词需要从url里接收,http://localhost:8000/search?keyword=地球.通过前面的进 ...
- Xamarin+Prism开发详解一:PCL跨平台类库与Profile的关系
在[Xamarin+Prism小试牛刀:定制跨平台Outlook邮箱应用]中提到过以下错误,不知道大伙还记得不: 无法安装程序包"Microsoft.Identity.Client 1.0. ...
- CRL快速开发框架系列教程七(使用事务)
本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...
- 【算法】C语言实现数组的动态分配
C语言实现数组的动态分配 作者:白宁超 2016年10月27日20:13:13 摘要:数据结构和算法对于编程的意义不言而喻,具有指导意义的.无论从事算法优化方向研究,还是大数据处理,亦或者网站开发AP ...
- ls: 无法访问/usr/sbin/smartctl: 没有那个文件或目录
环境:RHEL6.5 + Oracle 11.2.0.4 RAC 在安装RAC时,检查时缺少包 cvuqdisk-1.0.9-1,oracle提供脚本修复安装. 但在执行时报错: [root@orad ...
- ZKWeb网页框架1.3正式发布
本次更新的内容有 更新引用包版本 Microsoft.AspNetCore.Hosting.Abstractions 1.1.0 Microsoft.AspNetCore.Http.Abstracti ...
- Jqprint实现页面打印
好些项目需要实现页面打印,特别是一些后台管理类系统,下面介绍一款轻量级的打印插件: 1.实现页面打印要引入jQuery和Jqprint.点击下载Jqprint插件 <script languag ...
- css3更改input单选和多选的样式
在项目开发中我们经常会遇到需要更改input单选和多选样式的情况,今天就给大家介绍一种简单改变input单选和多选样式的办法. 在这之前先简单介绍一下:before伪类 :before 选择器向选定的 ...
- 当 IDENTITY_INSERT 设置为 OFF 时,不能为表 'T_Shell' 中的标识列插入显式值。
--允许将显示值插入表的标识列中-ON:允许 OFF:不允许set identity_insert T_shell ONset identity_insert T_Shell OFF
- [Hadoop in Action] 第6章 编程实践
Hadoop程序开发的独门绝技 在本地,伪分布和全分布模式下调试程序 程序输出的完整性检查和回归测试 日志和监控 性能调优 1.开发MapReduce程序 [本地模式] 本地模式 ...