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包作为标准库的一 ...
随机推荐
- Javascript生成二维码(QR)
网络上已经有非常多的二维码编码和解码工具和代码,很多都是服务器端的,也就是说需要一台服务器才能提供二维码的生成.本着对服务器性能的考虑,这种小事情都让服务器去做,感觉对不住服务器,尤其是对于大流量的网 ...
- HTML 事件(一) 事件的介绍
本篇主要介绍HTML中的事件知识:事件相关术语.DOM事件规范.事件对象. 其他事件文章 1. HTML 事件(一) 事件的介绍 2. HTML 事件(二) 事件的注册与注销 3. HTML 事件(三 ...
- HTML 事件(四) 模拟事件操作
本篇主要介绍HTML DOM中事件的模拟操作. 其他事件文章 1. HTML 事件(一) 事件的介绍 2. HTML 事件(二) 事件的注册与注销 3. HTML 事件(三) 事件流与事件委托 4. ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(76)-微信公众平台开发-网页授权
前言 网页授权是:应用或者网站请求你用你的微信帐号登录,同意之后第三方应用可以获取你的个人信息 网上说了一大堆参数,实际很难理解和猜透,我们以实际的代码来演示比较通俗易懂 配置 实现之前我们必须配置用 ...
- SQL Server-聚焦UNIOL ALL/UNION查询(二十三)
前言 本节我们来看看有关查询中UNION和UNION ALL的问题,简短的内容,深入的理解,Always to review the basics. 初探UNION和UNION ALL 首先我们过一遍 ...
- Javascript正则对象方法与字符串正则方法总结
正则对象 var reg = new Regexp('abc','gi') var reg = /abc/ig 正则方法 test方法(测试某个字符串是否匹配) var str = 'abc123'; ...
- winform异步加载数据到界面
做一个学习记录. 有两个需求: 1.点击按钮,异步加载数据,不卡顿UI. 2.把获取的数据加载到gridview上面. 对于需求1,2,代码如下: public delegate void ShowD ...
- python基础
内容概要: 一.python2 or python3 目前大多使用python2.7,随着时间的推移,python3将会成为python爱好者的主流. python2和3区别: 1.PRINT IS ...
- 分页插件--根据Bootstrap Paginator改写的js插件
刚刚出来实习,之前实习的公司有一个分页插件,和后端的数据字典约定好了的,基本上是看不到内部是怎么实现的,新公司是做WPF的,好像对于ASP.NET的东西不多,导师扔了一个小系统给我和另一个同事,指了两 ...
- ESLint的使用笔记
原文地址:https://csspod.com/getting-started-with-eslint/?utm_source=tuicool&utm_medium=referral 在团队协 ...