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. CSS 特殊属性介绍之 pointer-events

    首先看一下 MDN 上关于 pointer-events 的介绍: CSS属性 pointer-events 允许作者控制特定的图形元素在何时成为鼠标事件的 target.当未指定该属性时,SVG 内 ...

  2. 从零开始编写自己的C#框架(28)——建模、架构与框架

    文章写到这里,我一直在犹豫是继续写针对中小型框架的设计还是写些框架设计上的进阶方面的内容?对于中小型系统来说,只要将前面的内容进行一下细化,写上二三十章具体开发上的细节,来说明这个通用框架怎么开发的就 ...

  3. CRL快速开发框架系列教程三(更新数据)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  4. 《JavaScript设计模式与开发实践》整理

    最近在研读一本书<JavaScript设计模式与开发实践>,进阶用的. 一.高阶函数 高阶函数是指至少满足下列条件之一的函数. 1. 函数可以作为参数被传递. 2. 函数可以作为返回值输出 ...

  5. 【Big Data】HADOOP集群的配置(一)

    Hadoop集群的配置(一) 摘要: hadoop集群配置系列文档,是笔者在实验室真机环境实验后整理而得.以便随后工作所需,做以知识整理,另则与博客园朋友分享实验成果,因为笔者在学习初期,也遇到不少问 ...

  6. android Notification介绍

    如果要添加一个Notification,可以按照以下几个步骤 1:获取NotificationManager: NotificationManager m_NotificationManager=(N ...

  7. ola.hallengren的SQL Server维护脚本

    ola.hallengren的SQL Server维护脚本 下载地址 http://files.cnblogs.com/files/lyhabc/ola.hallengrenMaintenanceSo ...

  8. ASP.NET MVC 使用 Petapoco 微型ORM框架+NpgSql驱动连接 PostgreSQL数据库

    前段时间在园子里看到了小蝶惊鸿 发布的有关绿色版的Linux.NET——“Jws.Mono”.由于我对.Net程序跑在Linux上非常感兴趣,自己也看了一些有关mono的资料,但是一直没有时间抽出时间 ...

  9. Xamarin.Android-用ZXing实现二维码扫描以及连续扫描

    一.前言 本文的内容有两个基础:ZXing.Net和ZXing.Net.Mobile ZXing.Net:ZXing的C#实现,主要封装了各种二维码的编码.解码等跨平台的算法 ZXing.Net.Mo ...

  10. Windows 7 上安装Visual Studio 2015 失败解决方案

    安装之前先要看看自己的系统支不支持,具体的可以看:https://www.visualstudio.com/en-us/visual-studio-2015-system-requirements-v ...