在使用 Tornado 的过程中产生了以下疑问:

  • 什么时候需要给函数增加 @tornado.gen.coroutine
  • 什么时候调用函数需要 yield

@tornado.gen.coroutineyield 是如何工作的

包含 yield 的函数是一个 generator[1]。@gen.coroutine 通过 yield 与 generator 沟通、通过返回 Future 与协程的调用者沟通。

具体沟通情况:

  • @gen.coroutine 收到从 generator 返回的 Future
  • "unwraps" Future 获得结果
  • 将结果发送回 generator 以作为 yield 表达式的结果

如何调用协程

上文提到,

@gen.coroutine 通过返回 Future 与协程的调用者沟通

所以我们必须 "unwraps" 这个 Future 才能得到结果。

所以在绝大部分情况下,任何调用协程的函数本身必须是一个协程,并且在调用中要使用 yield

@gen.coroutine
def good_call():
# yield will unwrap the Future returned by divide() and raise
# the exception.
yield divide(1, 0)

注意,yield 只有在 @gen.coroutine 中才会 "unwraps" 一个 Future,如果没有 @gen.coroutine,那么 yield 只会将该函数变为一个而普通的生成器,比如下面两个例子。

  • 错误的
import tornado.gen
from tornado.ioloop import IOLoop
from tornado.gen import Return @tornado.gen.coroutine
def call_me():
raise Return('result') def f():
r = yield call_me()
print(r) # tornado.gen.BadYieldError: yielded unknown object <generator object f at 0x104a34320> IOLoop.current().run_sync(f)

错误的原因是:run_sync 会调用 f(),然后尝试将 f() 的结果转换为 Future,转换的函数如下:

# env/lib/python2.7/site-packages/tornado/gen.py:1259
def convert_yielded(yielded):
"""Convert a yielded object into a `.Future`. The default implementation accepts lists, dictionaries, and Futures. If the `~functools.singledispatch` library is available, this function
may be extended to support additional types. For example:: @convert_yielded.register(asyncio.Future)
def _(asyncio_future):
return tornado.platform.asyncio.to_tornado_future(asyncio_future) .. versionadded:: 4.1
"""
# Lists and dicts containing YieldPoints were handled earlier.
if yielded is None:
return moment
elif isinstance(yielded, (list, dict)):
return multi(yielded)
elif is_future(yielded):
return yielded
elif isawaitable(yielded):
return _wrap_awaitable(yielded)
else:
raise BadYieldError("yielded unknown object %r" % (yielded,))

由于 f() 返回的是一个 generator 对象,不符合转换的要求,所以报错。如果给 f() 加上 @tornado.gen.coroutine,那么装饰器会将 f() 返回的结果转换为 Future,符合 elif is_future(yielded):,也就能顺利运行。

  • 正确的
import tornado.gen
from tornado.ioloop import IOLoop
from tornado.gen import Return @tornado.gen.coroutine
def call_me():
raise Return('result') @tornado.gen.coroutine
def f():
r = yield call_me()
print(r) # result IOLoop.current().run_sync(f)

总结

  • 当调用一个协程时,@tornado.gen.coroutineyield 必须同时出现调用函数中
  • 如果只是在协程中执行操作或者直接返回结果,有 @tornado.gen.coroutine 和 return(raise Return)就够了

参考

  1. https://docs.python.org/2.4/ref/yield.html
  2. http://www.tornadoweb.org/en/stable/guide/coroutines.html#how-it-works

Tornado @tornado.gen.coroutine 与 yield的更多相关文章

  1. 使用tornado的gen.coroutine进行异步编程

    在tornado3发布之后,强化了coroutine的概念,在异步编程中,替代了原来的gen.engine, 变成现在的gen.coroutine.这个装饰器本来就是为了简化在tornado中的异步编 ...

  2. Tornado中gen.coroutine详解

    1.gen.coroutine的作用 自动执行生成器 2.Future对象 在介绍异步使用之前,先了解一下Future对象的作用. Future简单可以理解为一个占位符,将来会执行的对象,类似java ...

  3. Tornado源码分析系列之一: 化异步为'同步'的Future和gen.coroutine

    转自:http://blog.nathon.wang/2015/06/24/tornado-source-insight-01-gen/ 用Tornado也有一段时间,Tornado的文档还是比较匮乏 ...

  4. 如何捕捉@tornado.gen.coroutine里的异常

    from tornado import gen from tornado.ioloop import IOLoop @gen.coroutine def throw(a,b): try: a/b ra ...

  5. 使用tornado的gen模块改善程序性能

    之前在公司的一个模块,需要从另一处url取得数据,我使用了Python的一个很著名的lib,叫做requests.但是这样做极大的降低了程序的性能,因为tornado是单线程的,它使用了所谓的reac ...

  6. yield与gen.coroutine

    def d(): for i in range(2): yield i def b(): yield d() print("b") yield "bb" def ...

  7. 【Unity】协程Coroutine及Yield常见用法

    最近学习协程Coroutine,参考了别人的文章和视频教程,感觉协程用法还是相当灵活巧妙的,在此简单总结,方便自己以后回顾.Yield关键字的语意可以理解为“暂停”. 首先是yield return的 ...

  8. tornado异步请求的理解(转)

    tornado异步请求的理解 http://www.kankanews.com/ICkengine/archives/88953.shtml 官网第一段话: Tornado is a Python w ...

  9. PythonWEB框架之Tornado

    前言 Tornado(龙卷风)和Django一样是Python中比较主流的web框架,Tornado 和现在的主流 Web 服务器框架也有着明显的区别:Tornado自带socket,并且实现了异步非 ...

随机推荐

  1. cocos2d-x onMouseMove中CCTouch *pTouch参数的细节

    /**************************************************************************** Copyright (c) 2010 coc ...

  2. 0059 Spring MVC与浏览器间的JSON数据转换--@RequestBody--@ResponseBody--MappingJacson2HttpMessageConverter

    浏览器与服务器之间的数据交换有很多类型,不只是表单提交数据这一种,比如ajax技术就大量使用json.xml等,这时候就涉及到浏览器端和服务器端数据格式转换的问题,服务器端都是Java对象,需要把请求 ...

  3. 【转】Elasticsearch5.0 安装问题集锦

    Elasticsearch5.0 安装问题集锦 elasticsearch 5.0 安装过程中遇到了一些问题,通过查找资料几乎都解决掉了,这里简单记录一下 ,供以后查阅参考,也希望可以帮助遇到同样问题 ...

  4. 整合hibernate的lucene大数据模糊查询

      大数据模糊查询lucene 对工作单使用 like模糊查询时,实际上 数据库内部索引无法使用 ,需要逐条比较查询内容,效率比较低在数据量很多情况下, 提供模糊查询性能,我们可以使用lucene全文 ...

  5. NFC读卡APP

    # 设计文档 ### 简介----------------------------- 这个APP的功能是使用手机的NFC读卡器功能,做到读取卡片支持M1卡和CPU卡. ### 功能列表-------- ...

  6. Unix系统编程()信号:概念和概述

    这篇将一口气学完信号的基本概念,但是有很多的细节,所以篇幅较长,请做好心理准备. (他大爷的,一口气没有学完,太懒了) 有以下主题: 各种不同信号及其用途 内核可能为进程产生信号的环境,以及某一进程向 ...

  7. oracle初始操作

    oracle登录 sqlplus  sys/oracle as sysdba 这个登录之后呢 会出现这个: Connected to an idle instance. 这一步是连接上 [oracle ...

  8. Linux samba 服务的配置

    今天有个学生问我 samba 服务怎么配置,所以晚上特意研究一下怎么配置这个服务. 过程如下: sudo apt-get install samba samba-common // 安装 samba ...

  9. CSS(五):背景、列表、超链接伪类、鼠标形状控制属性

    一.背景属性 1.背景属性用来设置页面元素的背景样式. 2.常见背景属性 属性 描述 background-color 用来设置页面的背景色,取值如red,#ff0000 background-ima ...

  10. 使用pjsip传输已经编码的视频

    http://blog.chinaunix.net/uid-15063109-id-4445165.html ————————————————————————————————————————————— ...