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中的特殊语法:filter、map、reduce、lambda介绍
Apr 14 Python
Python正则捕获操作示例
Aug 19 Python
python微信跳一跳系列之棋子定位颜色识别
Feb 26 Python
django用户注册、登录、注销和用户扩展的示例
Mar 19 Python
python实现彩票系统
Jun 28 Python
如何使用django的MTV开发模式返回一个网页
Jul 22 Python
通过python3实现投票功能代码实例
Sep 26 Python
Python socket模块ftp传输文件过程解析
Nov 05 Python
Python数据可视化:箱线图多种库画法
Nov 06 Python
Python 读取有公式cell的结果内容实例方法
Feb 17 Python
Keras构建神经网络踩坑(解决model.predict预测值全为0.0的问题)
Jul 07 Python
pandas针对excel处理的实现
Jan 15 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新手上路(三)
2006/10/09 PHP
PHP 网络开发详解之远程文件包含漏洞
2010/04/25 PHP
PHP 自定义错误处理函数trigger_error()
2013/03/26 PHP
destoon文章模块调用企业会员资料的方法
2014/08/22 PHP
Zend Framework教程之Zend_Form组件实现表单提交并显示错误提示的方法
2016/03/21 PHP
PHP新特性之字节码缓存和内置服务器
2017/08/11 PHP
js 针对html DOM元素操作等经验累积
2014/03/11 Javascript
Jquery给基本控件的取值、赋值示例
2014/05/23 Javascript
JavaScript使用yield模拟多线程的方法
2015/03/19 Javascript
JS实现浏览器状态栏文字从右向左弹出效果代码
2015/10/27 Javascript
js实现交通灯效果
2017/01/13 Javascript
原生js开发的日历插件
2017/02/04 Javascript
基于vue.js轮播组件vue-awesome-swiper实现轮播图
2017/03/17 Javascript
jQuery实现表格冻结顶栏效果
2017/08/20 jQuery
深入理解vue-router之keep-alive
2017/08/31 Javascript
浅谈Angular 中何时取消订阅
2017/11/22 Javascript
Angular5中调用第三方js插件的方法
2018/02/26 Javascript
实用的Vue开发技巧
2019/05/30 Javascript
[01:05:12]2014 DOTA2国际邀请赛中国区预选赛 TongFu VS CIS-GAME
2014/05/21 DOTA
python文件读写操作与linux shell变量命令交互执行的方法
2015/01/14 Python
python在windows和linux下获得本机本地ip地址方法小结
2015/03/20 Python
在Python中使用正则表达式的方法
2015/08/13 Python
Python通过调用mysql存储过程实现更新数据功能示例
2018/04/03 Python
django自带serializers序列化返回指定字段的方法
2019/08/21 Python
python导入不同目录下的自定义模块过程解析
2019/11/18 Python
python调用HEG工具批量处理MODIS数据的方法及注意事项
2020/02/18 Python
意大利体育用品网上商城:Nencini Sport
2016/08/18 全球购物
求最大连续递增数字串(如"ads3sl456789DF3456ld345AA"中的"456789")
2015/09/11 面试题
风险评估实施方案
2014/03/09 职场文书
员工生日活动方案
2014/08/24 职场文书
学生会干部自我鉴定2014
2014/09/18 职场文书
黄埔军校观后感
2015/06/10 职场文书
大学校园招聘会感想
2015/08/10 职场文书
安全教育日主题班会
2015/08/13 职场文书
Spring Boot 实现敏感词及特殊字符过滤处理
2021/06/29 Java/Android
Apache Linkis 中间件架构及快速安装步骤
2022/03/16 Servers