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


Posted in Python onSeptember 11, 2016

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)

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

Python 相关文章推荐
Python三元运算实现方法
Jan 12 Python
Python使用MYSQLDB实现从数据库中导出XML文件的方法
May 11 Python
python实现xlsx文件分析详解
Jan 02 Python
Python实现识别手写数字 简易图片存储管理系统
Jan 29 Python
python读取文件名称生成list的方法
Apr 27 Python
详解关于Django中ORM数据库迁移的配置
Oct 08 Python
解决sublime+python3无法输出中文的问题
Dec 12 Python
使用python将请求的requests headers参数格式化方法
Jan 02 Python
Python操作多维数组输出和矩阵运算示例
Nov 28 Python
Python发起请求提示UnicodeEncodeError错误代码解决方法
Apr 21 Python
Python基于xlutils修改表格内容过程解析
Jul 28 Python
Python使用psutil库对系统数据进行采集监控的方法
Aug 23 Python
Python中使用asyncio 封装文件读写
Sep 11 #Python
Python 如何访问外围作用域中的变量
Sep 11 #Python
Python优化技巧之利用ctypes提高执行速度
Sep 11 #Python
Python 中的with关键字使用详解
Sep 11 #Python
Python冒泡排序注意要点实例详解
Sep 09 #Python
通过5个知识点轻松搞定Python的作用域
Sep 09 #Python
python验证码识别的实例详解
Sep 09 #Python
You might like
thinkphp实现分页显示功能
2016/12/03 PHP
详解Yii实现分页的两种方法
2017/01/14 PHP
详解yii2实现分库分表的方案与思路
2017/02/03 PHP
使用PHP开发留言板功能
2019/11/19 PHP
js与jquery中获取当前鼠标的x、y坐标位置的代码
2011/05/23 Javascript
Javascript优化技巧之短路表达式详细介绍
2015/03/27 Javascript
网页从弹窗页面单选框传值至父页面代码分享
2015/09/29 Javascript
html、css和jquery相结合实现简单的进度条效果实例代码
2016/10/24 Javascript
JS中如何实现点击a标签返回页面顶部的问题
2017/01/19 Javascript
Bootstrap模态框使用详解
2017/02/15 Javascript
NodeJS处理Express中异步错误
2017/03/26 NodeJs
详解React-Native全球化多语言切换工具库react-native-i18n
2017/11/03 Javascript
开发Vue树形组件的示例代码
2017/12/21 Javascript
完美解决axios跨域请求出错的问题
2018/02/05 Javascript
JavaScript实现简单动态进度条效果
2018/04/06 Javascript
JavaScript变速动画函数封装添加任意多个属性
2019/04/03 Javascript
在VUE中实现文件下载并判断状态的方法
2019/11/08 Javascript
Vue+Vuex实现自动登录的知识点详解
2020/03/04 Javascript
微信小程序自定义navigationBar顶部导航栏适配所有机型(附完整案例)
2020/04/26 Javascript
原生js实现放大镜组件
2021/01/22 Javascript
[03:12]完美世界DOTA2联赛PWL DAY6集锦
2020/11/05 DOTA
numpy中矩阵合并的实例
2018/06/15 Python
Python如何批量获取文件夹的大小并保存
2020/03/31 Python
在求职信中如何凸显个人优势
2013/10/30 职场文书
标准自荐信范文
2014/01/29 职场文书
大学生军训自我鉴定
2014/02/12 职场文书
期末评语大全
2014/05/04 职场文书
2014年母亲节寄语
2014/05/07 职场文书
专家推荐信模板
2014/05/09 职场文书
爱晚亭导游词
2015/02/09 职场文书
捐书活动倡议书
2015/04/27 职场文书
道歉情书大全
2015/05/12 职场文书
婚庆主持词大全
2015/06/30 职场文书
什么是执行力?9个故事告诉您:成功绝非偶然!
2019/07/05 职场文书
MySQL的安装与配置详细教程
2021/06/26 MySQL
OpenStack虚拟机快照和增量备份实现方法
2022/04/04 Servers