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中使用poplib模块收取邮件的教程
Apr 29 Python
PyQt5打开文件对话框QFileDialog实例代码
Feb 07 Python
Python cookbook(数据结构与算法)对切片命名清除索引的方法
Mar 13 Python
python对html过滤处理的方法
Oct 21 Python
python中for循环把字符串或者字典添加到列表的方法
Jul 20 Python
python集合的创建、添加及删除操作示例
Oct 08 Python
Python3 使用selenium插件爬取苏宁商家联系电话
Dec 23 Python
浅谈Django中的QueryDict元素为数组的坑
Mar 31 Python
基于python纯函数实现井字棋游戏
May 27 Python
简单的Python人脸识别系统
Jul 14 Python
python自然语言处理之字典树知识总结
Apr 25 Python
python必学知识之文件操作(建议收藏)
May 30 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不用递归实现无限分级的例子分享
2014/04/18 PHP
php版微信自定义回复功能示例
2016/12/05 PHP
php实现的二分查找算法示例
2017/06/20 PHP
不常用但很实用的PHP预定义变量分析
2019/06/25 PHP
Laravel 实现Eloquent模型分组查询并返回每个分组的数量 groupBy()
2019/10/23 PHP
实例化php类时传参的方法分析
2020/06/05 PHP
js用图作提交按钮或超连接
2008/03/26 Javascript
JS拖动技术 关于setCapture使用
2010/12/09 Javascript
Javascript中innerHTML用法实例分析
2015/01/12 Javascript
jQuery使用attr()方法同时设置多个属性值用法实例
2015/03/26 Javascript
JS处理json日期格式化问题
2015/10/01 Javascript
js下将金额数字每三位一逗号分隔
2016/02/19 Javascript
全面解析bootstrap格子布局
2016/05/22 Javascript
js弹出窗口返回值的简单实例
2016/05/28 Javascript
微信小程序(应用号)开发新闻客户端实例
2016/10/24 Javascript
有关JS中的0,null,undefined,[],{},'''''''',false之间的关系
2017/02/14 Javascript
JavaScript ES6中const、let与var的对比详解
2017/06/18 Javascript
express如何使用session与cookie的方法
2018/01/30 Javascript
jQuery实现的监听导航滚动置顶状态功能示例
2018/07/23 jQuery
Vue可自定义tab组件用法实例
2019/10/24 Javascript
vue-路由精讲 二级路由和三级路由的作用
2020/08/06 Javascript
[51:39]DOTA2-DPC中国联赛 正赛 Magma vs LBZS BO3 第二场 2月7日
2021/03/11 DOTA
python静态方法实例
2015/01/14 Python
Python Tkinter模块实现时钟功能应用示例
2018/07/23 Python
使用scrapy ImagesPipeline爬取图片资源的示例代码
2020/09/28 Python
使用python把xmind转换成excel测试用例的实现代码
2020/10/12 Python
Django Auth用户认证组件实现代码
2020/10/13 Python
python爬虫scrapy框架的梨视频案例解析
2021/02/20 Python
推荐10个CSS3 制作的创意下拉菜单效果
2014/02/11 HTML / CSS
Html5新标签解释及用法
2012/02/17 HTML / CSS
红色康乃馨酒店:Red Carnation Hotels
2017/06/22 全球购物
波兰补充商店:Muscle Power
2018/10/29 全球购物
英国高街奥特莱斯:Highstreet Outlet
2019/11/21 全球购物
领导调研接待方案
2014/02/27 职场文书
幼师个人总结范文
2015/02/28 职场文书
讲解Python实例练习逆序输出字符串
2022/05/06 Python