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中使用gzip模块压缩文件的简单教程
Apr 08 Python
Python去除字符串两端空格的方法
May 21 Python
Python fileinput模块使用实例
Jun 03 Python
Python基于PyGraphics包实现图片截取功能的方法
Dec 21 Python
利用python将pdf输出为txt的实例讲解
Apr 23 Python
举例讲解Python常用模块
Mar 08 Python
详解python中的time和datetime的常用方法
Jul 08 Python
Python中的几种矩阵乘法(小结)
Jul 10 Python
pandas DataFrame 警告(SettingWithCopyWarning)的解决
Jul 23 Python
Tensorflow安装问题: Could not find a version that satisfies the requirement tensorflow
Apr 20 Python
Python学习之os模块及用法
Jun 03 Python
Python实现学生管理系统并生成exe可执行文件详解流程
Jan 22 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
针对初学PHP者的疑难问答(2)
2006/10/09 PHP
php 数组排序 array_multisort与uasort的区别
2011/03/24 PHP
php获取ajax的headers方法与内容实例
2017/12/27 PHP
thinkphp5.1框架实现格式化mysql时间戳为日期的方式小结
2019/10/10 PHP
基于jquery的分页控件(C#)
2011/01/06 Javascript
JS小游戏之仙剑翻牌源码详解
2014/09/25 Javascript
全面了解函数声明与函数表达式、变量提升
2016/08/09 Javascript
vue开发心得和技巧分享
2016/10/27 Javascript
jQuery常见的选择器及用法介绍
2016/12/20 Javascript
a标签置灰不可点击的实现方法
2017/02/06 Javascript
vue组件Prop传递数据的实现示例
2017/08/17 Javascript
解决vue attr取不到属性值的问题
2018/09/18 Javascript
JavaScript JMap类定义与使用方法示例
2019/01/22 Javascript
使用p5.js实现动态GIF图片临摹重现
2019/10/23 Javascript
js实现秒表计时器
2019/12/16 Javascript
tracking.js实现前端人脸识别功能
2020/04/16 Javascript
浅谈JavaScript中this的指向更改
2020/07/28 Javascript
vue实现动态给id赋值,点击事件获取当前点击的元素的id操作
2020/11/09 Javascript
[45:10]NB vs Liquid Supermajor小组赛 A组胜者组决赛 BO3 第二场 6.2
2018/06/04 DOTA
基于ID3决策树算法的实现(Python版)
2017/05/31 Python
linecache模块加载和缓存文件内容详解
2018/01/11 Python
python-tkinter之按钮的使用,开关方法
2019/06/11 Python
django框架cookie和session用法实例详解
2019/12/10 Python
jenkins+python自动化测试持续集成教程
2020/05/12 Python
next在python中返回迭代器的实例方法
2020/12/15 Python
飞利浦比利时官方网站:Philips比利时
2016/08/24 全球购物
小学生爱国演讲稿
2014/04/25 职场文书
村主任群众路线教育实践活动个人对照检查材料思想汇报
2014/10/01 职场文书
学校师德师风整改措施
2014/10/27 职场文书
创先争优承诺书
2015/01/20 职场文书
部队2015年终工作总结
2015/04/02 职场文书
2015年学生会主席工作总结
2015/04/21 职场文书
工程款催款函
2015/06/24 职场文书
班委竞选稿范文
2015/11/21 职场文书
python全面解析接口返回数据
2022/02/12 Python
Sql Server 行数据的某列值想作为字段列显示的方法
2022/04/20 SQL Server