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通过urllib2爬网页上种子下载示例
Feb 24 Python
python实现支持目录FTP上传下载文件的方法
Jun 03 Python
python爬虫入门教程--HTML文本的解析库BeautifulSoup(四)
May 25 Python
python使用两种发邮件的方式smtp和outlook示例
Jun 02 Python
pandas筛选某列出现编码错误的解决方法
Nov 07 Python
元组列表字典(莫烦python基础)
Apr 03 Python
使用Python的OpenCV模块识别滑动验证码的缺口(推荐)
May 10 Python
python安装读取grib库总结(推荐)
Jun 24 Python
Python调用C语言程序方法解析
Jul 07 Python
Python 防止死锁的方法
Jul 29 Python
python3.9和pycharm的安装教程并创建简单项目的步骤
Feb 03 Python
Python中的xlrd模块使用整理
Jun 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实现json编码的方法
2015/07/30 PHP
PHP表单提交后引号前自动加反斜杠的原因及三种办法关闭php魔术引号
2015/09/30 PHP
php实现zip文件解压操作
2015/11/03 PHP
PHP获取redis里不存在的6位随机数应用示例【设置24小时过时】
2017/06/07 PHP
php模仿qq空间或朋友圈发布动态、评论动态、回复评论、删除动态或评论的功能(中)
2017/06/11 PHP
PHP读取、解析eml文件及生成网页的方法示例
2017/09/04 PHP
extjs form textfield的隐藏方法
2008/12/29 Javascript
jQuery基础知识filter()和find()实例说明
2010/07/06 Javascript
JavaScript 高级篇之闭包、模拟类,继承(五)
2012/04/07 Javascript
基于js disabled=&quot;false&quot;不起作用的解决办法
2013/06/26 Javascript
密码框显示提示文字jquery示例
2013/08/29 Javascript
浅谈JavaScript数据类型及转换
2015/02/28 Javascript
js实现精美的图片跟随鼠标效果实例
2015/05/16 Javascript
使用jspdf生成pdf报表
2015/07/03 Javascript
javaScript实现滚动新闻的方法
2015/07/30 Javascript
jQuery图片渐变特效的简单实现
2016/06/25 Javascript
js判断出两个字符串最大子串的函数实现方法
2016/11/01 Javascript
DOM事件探秘篇
2017/02/15 Javascript
angular select 默认值设置方法
2017/06/23 Javascript
原生js的ajax和解决跨域的jsonp(实例讲解)
2017/10/16 Javascript
jquery如何实现点击空白处隐藏元素
2017/12/05 jQuery
为vue-router懒加载时下载js的过程中添加loading提示避免无响应问题
2018/04/03 Javascript
ES6关于Promise的用法详解
2018/05/07 Javascript
vue+element实现表单校验功能
2019/05/20 Javascript
[01:33:59]真人秀《加油 DOTA》 第六期
2014/09/09 DOTA
Python修改Excel数据的实例代码
2013/11/01 Python
Python装饰器的执行过程实例分析
2018/06/04 Python
利用python批量爬取百度任意类别的图片的实现方法
2020/10/07 Python
python爬虫爬取淘宝商品比价(附淘宝反爬虫机制解决小办法)
2020/12/03 Python
HTML5本地数据库基础操作详解
2016/04/26 HTML / CSS
用C语言实现文件读写操作
2013/10/27 面试题
高中生毕业自我鉴定范文
2013/12/22 职场文书
公司端午节活动方案
2014/02/04 职场文书
卖车协议书范例
2014/09/16 职场文书
2015新员工工作总结范文
2015/10/15 职场文书
职业生涯规划书之大学四年
2019/08/07 职场文书