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 201

Python标准模块--concurrent.futures的更多相关文章

  1. Thread类的其他方法,同步锁,死锁与递归锁,信号量,事件,条件,定时器,队列,Python标准模块--concurrent.futures

    参考博客: https://www.cnblogs.com/xiao987334176/p/9046028.html 线程简述 什么是线程?线程是cpu调度的最小单位进程是资源分配的最小单位 进程和线 ...

  2. python 全栈开发,Day42(Thread类的其他方法,同步锁,死锁与递归锁,信号量,事件,条件,定时器,队列,Python标准模块--concurrent.futures)

    昨日内容回顾 线程什么是线程?线程是cpu调度的最小单位进程是资源分配的最小单位 进程和线程是什么关系? 线程是在进程中的 一个执行单位 多进程 本质上开启的这个进程里就有一个线程 多线程 单纯的在当 ...

  3. python全栈开发,Day42(Thread类的其他方法,同步锁,死锁与递归锁,信号量,事件,条件,定时器,队列,Python标准模块--concurrent.futures)

    昨日内容回顾 线程 什么是线程? 线程是cpu调度的最小单位 进程是资源分配的最小单位 进程和线程是什么关系? 线程是在进程中的一个执行单位 多进程 本质上开启的这个进程里就有一个线程 多线程 单纯的 ...

  4. Python标准模块--concurrent.futures(进程池,线程池)

    python为我们提供的标准模块concurrent.futures里面有ThreadPoolExecutor(线程池)和ProcessPoolExecutor(进程池)两个模块. 在这个模块里他们俩 ...

  5. Python标准模块--concurrent.futures 进程池线程池终极用法

    concurrent.futures 这个模块是异步调用的机制concurrent.futures 提交任务都是用submitfor + submit 多个任务的提交shutdown 是等效于Pool ...

  6. Python--day41--线程池--python标准模块concurrent.futures

    1,线程池代码示例:(注:进程池的话只要将以下代码中的ThreadPoolExecutor替换成ProcessPoolExecutor即可,这里不演示) import time from concur ...

  7. Python标准模块--threading

    1 模块简介 threading模块在Python1.5.2中首次引入,是低级thread模块的一个增强版.threading模块让线程使用起来更加容易,允许程序同一时间运行多个操作. 不过请注意,P ...

  8. Python标准模块--logging

    1 logging模块简介 logging模块是Python内置的标准模块,主要用于输出运行日志,可以设置输出日志的等级.日志保存路径.日志文件回滚等:相比print,具备如下优点: 可以通过设置不同 ...

  9. Python标准模块--importlib

    作者:zhbzz2007 出处:http://www.cnblogs.com/zhbzz2007 欢迎转载,也请保留这段声明.谢谢! 1 模块简介 Python提供了importlib包作为标准库的一 ...

随机推荐

  1. Javascript生成二维码(QR)

    网络上已经有非常多的二维码编码和解码工具和代码,很多都是服务器端的,也就是说需要一台服务器才能提供二维码的生成.本着对服务器性能的考虑,这种小事情都让服务器去做,感觉对不住服务器,尤其是对于大流量的网 ...

  2. HTML 事件(一) 事件的介绍

    本篇主要介绍HTML中的事件知识:事件相关术语.DOM事件规范.事件对象. 其他事件文章 1. HTML 事件(一) 事件的介绍 2. HTML 事件(二) 事件的注册与注销 3. HTML 事件(三 ...

  3. HTML 事件(四) 模拟事件操作

    本篇主要介绍HTML DOM中事件的模拟操作. 其他事件文章 1. HTML 事件(一) 事件的介绍 2. HTML 事件(二) 事件的注册与注销 3. HTML 事件(三) 事件流与事件委托 4.  ...

  4. ASP.NET MVC5+EF6+EasyUI 后台管理系统(76)-微信公众平台开发-网页授权

    前言 网页授权是:应用或者网站请求你用你的微信帐号登录,同意之后第三方应用可以获取你的个人信息 网上说了一大堆参数,实际很难理解和猜透,我们以实际的代码来演示比较通俗易懂 配置 实现之前我们必须配置用 ...

  5. SQL Server-聚焦UNIOL ALL/UNION查询(二十三)

    前言 本节我们来看看有关查询中UNION和UNION ALL的问题,简短的内容,深入的理解,Always to review the basics. 初探UNION和UNION ALL 首先我们过一遍 ...

  6. Javascript正则对象方法与字符串正则方法总结

    正则对象 var reg = new Regexp('abc','gi') var reg = /abc/ig 正则方法 test方法(测试某个字符串是否匹配) var str = 'abc123'; ...

  7. winform异步加载数据到界面

    做一个学习记录. 有两个需求: 1.点击按钮,异步加载数据,不卡顿UI. 2.把获取的数据加载到gridview上面. 对于需求1,2,代码如下: public delegate void ShowD ...

  8. python基础

    内容概要: 一.python2 or python3 目前大多使用python2.7,随着时间的推移,python3将会成为python爱好者的主流. python2和3区别: 1.PRINT IS ...

  9. 分页插件--根据Bootstrap Paginator改写的js插件

    刚刚出来实习,之前实习的公司有一个分页插件,和后端的数据字典约定好了的,基本上是看不到内部是怎么实现的,新公司是做WPF的,好像对于ASP.NET的东西不多,导师扔了一个小系统给我和另一个同事,指了两 ...

  10. ESLint的使用笔记

    原文地址:https://csspod.com/getting-started-with-eslint/?utm_source=tuicool&utm_medium=referral 在团队协 ...