asyncio 的 coroutine对象 与 Future对象使用指南

coroutine 与 Future 的关系

看起来两者是一样的,因为都可以用以下的语法来异步获取结果,

result = await future
result = await coroutine

实际上,coroutine 是生成器函数,它既可以从外部接受参数,也可以产生结果。使用 coroutine 的好处是,我们可以暂停一个函数,然后稍后恢复执行。比如在涉及到网路操作的情况下,能够停下函数直到响应到来。在停下的这段时间内,我们可以切换到其他任务继续执行。

而 Future 更像是 Javascript 中的 Promise 对象。它是一个占位符,其值会在将来被计算出来。在上述的例子中,当我们在等待网络 IO 函数完成时,函数会给我们一个容器,Promise 会在完成时填充该容器。填充完毕后,我们可以用回调函数来获取实际结果。

Task 对象是 Future 的子类,它将 coroutine 和 Future 联系在一起,将 coroutine 封装成一个 Future 对象。

一般会看到两种任务启动方法,

tasks = asyncio.gather(
  asyncio.ensure_future(func1()),
  asyncio.ensure_future(func2())
)
loop.run_until_complete(tasks)

tasks = [
  asyncio.ensure_future(func1()),
  asyncio.ensure_future(func2())
  ]
loop.run_until_complete(asyncio.wait(tasks))

ensure_future 可以将 coroutine 封装成 Task。asyncio.gather 将一些 Future 和 coroutine 封装成一个 Future。

asyncio.wait 则本身就是 coroutine。

run_until_complete 既可以接收 Future 对象,也可以是 coroutine 对象,

BaseEventLoop.run_until_complete(future)

Run until the Future is done.
If the argument is a coroutine object, it is wrapped by ensure_future().
Return the Future's result, or raise its exception.

Task 任务的正确退出方式

在 asyncio 的任务循环中,如果使用 CTRL-C 退出的话,即使捕获了异常,Event Loop 中的任务会报错,出现如下的错误,

Task was destroyed but it is pending!
task: <Task pending coro=<kill_me() done, defined at test.py:5> wait_for=<Future pending cb=[Task._wakeup()]>>

根据官方文档,Task 对象只有在以下几种情况,会认为是退出,

a result / exception are available, or that the future was cancelled

Task 对象的 cancel 和其父类 Future 略有不同。当调用 Task.cancel() 后,对应 coroutine 会在事件循环的下一轮中抛出 CancelledError 异常。使用 Future.cancelled() 并不能立即返回 True(用来表示任务结束),只有在上述异常被处理任务结束后才算是 cancelled。

故结束任务可以用

for task in asyncio.Task.all_tasks():
  task.cancel()

这种方法将所有任务找出并 cancel。

但 CTRL-C 也会将事件循环停止,所以有必要重启事件循环,

try:
  loop.run_until_complete(tasks)
except KeyboardInterrupt as e:
  for task in asyncio.Task.all_tasks():
    task.cancel()
  loop.run_forever() # restart loop
finally:
  loop.close()

在每个 Task 中捕获异常是必要的,如果不确定,可以使用

asyncio.gather(..., return_exceptions=True)

将异常转换为正常的结果返回。

(0)

相关推荐

  • 基于asyncio 异步协程框架实现收集B站直播弹幕

    前言 虽然标题是全站,但目前只做了等级 top 100 直播间的全天弹幕收集. 弹幕收集系统基于之前的B 站直播弹幕姬 Python 版修改而来.具体协议分析可以看上一篇文章. 直播弹幕协议是直接基于 TCP 协议,所以如果 B 站对类似我这种行为做反制措施,比较困难.应该有我不知道的技术手段来检测类似我这种恶意行为. 我试过同时连接 100 个房间,和连接单个房间 100 次的实验,都没有问题.>150 会被关闭链接. 直播间的选取 现在弹幕收集系统在选取直播间上比较简单,直接选取了等级 to

  • 探索Python3.4中新引入的asyncio模块

    使用 Simple Protocol asyncio.BaseProtocol 类是asyncio模块中协议接口(protocol interface)的一个常见的基类.asyncio.Protocolclass 继承自asyncio.BaseProtocol 并为stream protocols提供了一个接口.下面的代码演示了asyncio.Protocol 接口的一个简单实现,它的行为1就像一个echo server,同时,它还会在Python的控制台中输出一些信息.SimpleEchoPr

  • Python中使用asyncio 封装文件读写

    前言 和网络 IO 一样,文件读写同样是一个费事的操作. 默认情况下,Python 使用的是系统的阻塞读写.这意味着在 asyncio 中如果调用了 f = file('xx') f.read() 会阻塞事件循环. 本篇简述如何用 asyncio.Future 对象来封装文件的异步读写. 代码在 GitHub.目前仅支持 Linux. 阻塞和非阻塞 首先需要将文件的读写改为非阻塞的形式.在非阻塞情况下,每次调用 read 都会立即返回,如果返回值为空,则意味着文件操作还未完成,反之则是读取的文件

  • 在Python3中使用asyncio库进行快速数据抓取的教程

    web数据抓取是一个经常在python的讨论中出现的主题.有很多方法可以用来进行web数据抓取,然而其中好像并没有一个最好的办法.有一些如scrapy这样十分成熟的框架,更多的则是像mechanize这样的轻量级库.DIY自己的解决方案同样十分流行:你可以使用requests.beautifulsoup或者pyquery来实现. 方法如此多样的原因在于,数据"抓取"实际上包括很多问题:你不需要使用相同的工具从成千上万的页面中抓取数据,同时使一些Web工作流自动化(例如填一些表单然后取回

  • asyncio 的 coroutine对象 与 Future对象使用指南

    coroutine 与 Future 的关系 看起来两者是一样的,因为都可以用以下的语法来异步获取结果, result = await future result = await coroutine 实际上,coroutine 是生成器函数,它既可以从外部接受参数,也可以产生结果.使用 coroutine 的好处是,我们可以暂停一个函数,然后稍后恢复执行.比如在涉及到网路操作的情况下,能够停下函数直到响应到来.在停下的这段时间内,我们可以切换到其他任务继续执行. 而 Future 更像是 Jav

  • python中利用Future对象回调别的函数示例代码

    前言 本文主要给大家介绍了关于python中用Future对象回调别的函数的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. Future对象也可以像协程一样,当它设置完成结果时,就可以立即进行回调别的函数 例子如下: import asyncio import functools def callback(future, n): print('{}: future done: {}'.format(n, future.result())) async def regi

  • python中利用Future对象异步返回结果示例代码

    前言 本文主要给大家介绍了关于python中用Future对象异步返回结果的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 一个Future是用来表示将来要完成的结果,异步循环可以自动完成对这种对象的状态触发. 例子如下: import asyncio def mark_done(future, result): print('setting future result to {!r}'.format(result)) future.set_result(result

  • python中利用await关键字如何等待Future对象完成详解

    前言 本文主要给大家介绍了关于python用await关键字等待Future对象完成的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 在下面的例子里,演示了怎么样使用await来等Future对象设置结果完成 示例代码如下: import asyncio def mark_done(future, result): print('setting future result to {!r}'.format(result)) future.set_result(resul

  • C++11之std::future对象的使用以及说明

    目录 std::future介绍 细节说明 wait系列操作 get操作 时序图 std::future使用 总结 std::future介绍 在前面几篇文章中基本都用到thread对象,它是C++11中提供异步创建多线程的工具. 但是我们想要从线程中返回异步任务结果,一般需要依靠全局变量:从安全角度看,有些不妥:为此C++11提供了std::future类模板,future对象提供访问异步操作结果的机制,很轻松解决从异步任务中返回结果. 在C++标准库中,有两种“期望” 使用两种类型模板实现

  • 基于JavaScript将表单序列化类型的数据转化成对象的处理(允许对象中包含对象)

    表单序列化类型的数据是指url传递的数据的格式,形如"key=value&key=value&key=value"这样的key/value的键值对.一般来说使用jQuery的$.fn.serialize函数能达到这样的效果.如何将这样的格式转化为对象? 我们知道使用jQuery的$.fn.serializeArray函数得到的是一个如下结构的对象 [ { name: "startTime" value: "2015-12-02 00:00:

  • JS操作xml对象转换为Json对象示例

    最近在处理一个前端功能的时候,遇到了一个问题,原本的系统是使用的xml来存储数据的,而在新的系统上,想要转换为json对象存储,于是就考虑到直接将xml对象转换为json对象. 目前为止,通用的转换方式我还没有找到,只有根据已知的xml对象结构来使用for循环不断地赋值. var xml = ······;//获取xml对象 var objList = []; for(var i = 0;i<xml.childNodes.length;i++){ var obj = {}; obj.attrib

  • 原生js实现复制对象、扩展对象 类似jquery中的extend()方法

    jq的extend()方法能很方便的实现扩展对象方法,语法如下:$.extend(obj1,boj2,obj3); 现在要实现的是:原生js实现复制对象,扩展对象,类似jq中的extend()方法,具体实例如下: 现有3个对象字面量: var o1={hello:1,old:555}, o2 = { abc: 55555555, hello: 2, fun: function() { alert(111); } }, o3={third:9999}; 实现目标: 复制o1对象,把 o2,o3的对

  • jQuery对象和Javascript对象之间转换的实例代码

    复制代码 代码如下: 以下是本人的一些分享,我热爱编程,希望能多交编程的爱好者,如果你也是其中一名,那么请加好友,大家关注一下,下面的文章是自己觉得一些有用的东西,留下来给自己当笔记,当然也希望能帮助到你,首先感谢你的阅读~! 如果我们在用jQuery作为客户端页面的脚本,时常都会涉及到jQuery对象和Javascript对象的相互转换.因为,DOM对象就是Javascript 固有的一些对象操作.DOM 对象能使用Javascript 固有的方法,但是不能使用 jQuery 里的方法.所以,

  • JavaScript浏览器对象之一Window对象详解

    JavaScript提供了一组以window为核心的对象,实现了对浏览器窗口的访问控制.JavaScript中定义了6种重要的对象: window对象 表示浏览器中打开的窗口: document对象 表示浏览器中加载页面的文档对象: location对象包含了浏览器当前的URL信息: navigation对象 包含了浏览器本身的信息: screen对象 包含了客户端屏幕及渲染能力的信息: history对象 包含了浏览器访问网页的历史信息. 除了window对象之外,其他的5个对象都是windo

随机推荐