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实现简单状态框架的方法
Mar 19 Python
Python enumerate索引迭代代码解析
Jan 19 Python
对python中两种列表元素去重函数性能的比较方法
Jun 29 Python
python traceback捕获并打印异常的方法
Aug 31 Python
python导入pandas具体步骤方法
Jun 23 Python
Windows平台Python编程必会模块之pywin32介绍
Oct 01 Python
python爬虫添加请求头代码实例
Dec 28 Python
Python爬虫开发与项目实战
Dec 16 Python
python中类与对象之间的关系详解
Dec 16 Python
pycharm 多行批量缩进和反向缩进快捷键介绍
Jan 15 Python
Python爬虫之爬取哔哩哔哩热门视频排行榜
Apr 28 Python
Python多线程 Queue 模块常见用法
Jul 04 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计算两个坐标(经度,纬度)之间距离的方法
2015/04/17 PHP
PHP魔术方法的使用示例
2015/06/23 PHP
Symfony2创建页面实例详解
2016/03/18 PHP
PHP中PDO事务处理操作示例
2018/05/02 PHP
thinkphp框架实现路由重定义简化url访问地址的方法分析
2020/04/04 PHP
javascript 面向对象编程基础:继承
2009/08/21 Javascript
JavaScript脚本判断蜘蛛来源的方法
2015/09/22 Javascript
JQuery实现DIV其他动画效果的简单实例
2016/09/18 Javascript
js前端实现多图图片上传预览的两个方法(推荐)
2016/11/18 Javascript
jQuery实现二维码扫描功能
2017/01/09 Javascript
Bootstrap面板学习使用
2017/02/09 Javascript
jquery横向纵向鼠标滚轮全屏切换
2017/02/27 Javascript
微信小程序实现动态改变view标签宽度和高度的方法【附demo源码下载】
2017/12/05 Javascript
nodejs取得当前执行路径的方法
2018/05/13 NodeJs
vue解决使用webpack打包后keep-alive不生效的方法
2018/09/01 Javascript
Element Input组件分析小结
2018/10/11 Javascript
Node.js事件的正确使用方法
2019/04/05 Javascript
JS实现星星海特效
2019/12/24 Javascript
vue data变量相互赋值后被实时同步的解决步骤
2020/08/05 Javascript
js+css实现扇形导航效果
2020/08/18 Javascript
javascript代码实现简易计算器
2021/01/25 Javascript
Python爬取网易云音乐热门评论
2017/03/31 Python
Python3用tkinter和PIL实现看图工具
2018/06/21 Python
对pandas中两种数据类型Series和DataFrame的区别详解
2018/11/12 Python
python 读取Linux服务器上的文件方法
2018/12/27 Python
Python插件机制实现详解
2020/05/04 Python
Selenium webdriver添加cookie实现过程详解
2020/08/12 Python
python 基于Apscheduler实现定时任务
2020/12/15 Python
JBL美国官方商店:扬声器、耳机等
2019/12/01 全球购物
.NET常见笔试题集
2012/12/01 面试题
供货协议书
2014/04/22 职场文书
学校三节实施方案
2014/06/09 职场文书
总经理检讨书
2014/09/15 职场文书
励志语录:只有自己足够强大,才能不被别人践踏
2020/01/09 职场文书
Python基础之pandas数据合并
2021/04/27 Python
MySQL分区表实现按月份归类
2021/11/01 MySQL