转自:http://blog.xiaogaozi.org/2012/09/21/understanding-tornado-dot-gen/

理解 tornado.gen

SEP 21ST, 2012

Tornado 通过 @asynchronous decorator 来实现异步请求,但使用的时候必须将 request handler 和 callback 分离开,tornado.gen 模块可以帮助我们在一个函数里完成这两个工作。下面是官方的一个例子:

1
2
3
4
5
6
7
8
class GenAsyncHandler(RequestHandler):
@asynchronous
@gen.engine
def get(self):
http_client = AsyncHTTPClient()
response = yield gen.Task(http_client.fetch, "http://example.com")
do_something_with_response(response)
self.render("template.html")

这里用到了两个 decorator 稍显复杂,第一个 @asynchronous 会首先被执行,它的主要工作就是将 RequestHandler 的 _auto_finish 属性置为 false,如下:

web.pydownload

1
2
3
4
5
6
7
8
9
10
def asynchronous(method):
@functools.wraps(method)
def wrapper(self, *args, **kwargs):
if self.application._wsgi:
raise Exception("@asynchronous is not supported for WSGI apps")
self._auto_finish = False
with stack_context.ExceptionStackContext(
self._stack_context_handle_exception):
return method(self, *args, **kwargs)
return wrapper

接着就是最重要的 @gen.engine,这里充分利用了 generator 的各种特性,首先来看 @gen.engine 的实现(我删减了部分代码以简化理解):

gen.pydownload

1
2
3
4
5
6
7
8
9
def engine(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
gen = func(*args, **kwargs)
if isinstance(gen, types.GeneratorType):
runner = Runner(gen)
runner.run()
return
return wrapper

局部变量 gen 代表第一段代码里的 get 函数,因为 get 包含了 yield 语句,因此成为了一个 generator。注意这里 get 并没有被执行,只是赋给了 gen。接下来是运行 Runner 对象的 run 函数。在理解 run 之前需要知道 generator 是通过调用 next() 或者 send() 来启动,启动之后会在遇到 yield 的地方 hold 住,然后将 yield 后面的语句的返回值返回给调用者,generator 此时即处于暂停运行状态,所有上下文都会保存。再次调用 next() 或 send() 便会恢复 generator 的运行,如果不再遇到 yield 语句就会抛出 StopIteration 异常。在恢复运行的同时 yield 语句本身会有返回值,如果是通过调用 next() 来恢复的,那么返回值永远是 None,而如果是通过 send() 则返回值取决于传给 send() 的参数。更多关于 generator 的说明请参考官方文档

结合第一段的示例代码,可以想到 run 干的工作可能就是启动 generator,然后获得 gen.Task对象并调用 http_client.fetch 函数,等回调回来之后恢复 generator 的运行,最后将回调的返回值通过 send() 赋给 response。下面是我简化后的代码。

gen.pydownload

1
2
3
4
5
6
7
8
9
10
11
12
def run(self):
while True:
if not self.yield_point.is_ready():
return
next = self.yield_point.get_result()
try:
yielded = self.gen.send(next)
except StopIteration:
return
if isinstance(yielded, YieldPoint):
self.yield_point = yielded
self.yield_point.start(self)

第 3 行检查回调是否完成,第一次运行 run 总是会返回 True。第 5 行获取回调的返回值,同样的第一次运行返回的是 None。将 None 传给 send() 启动 generator,yielded 即是 gen.Task 对象,第 12 行调用 start 开始运行我们真正需要运行的函数,对应到示例代码就是http_client.fetch 函数,同时将 Runner 的 result_callback 作为回调函数。如下:

gen.pydownload

1
2
3
4
5
6
7
8
9
10
11
def result_callback(self, key):
def inner(*args, **kwargs):
if kwargs or len(args) > 1:
result = Arguments(args, kwargs)
elif args:
result = args[0]
else:
result = None
self.results[key] = result
self.run()
return inner

在得到回调返回值之后再次调用 run,通过 get_result 获取返回值,最后将返回值返回赋给 response,继续 request handler 的代码流程。

理解 tornado.gen的更多相关文章

  1. tornado.gen 模块解析

    转自:http://strawhatfy.github.io/2015/07/22/Tornado.gen/ 引言 注:正文中引用的 Tornado 代码除特别说明外,都默认引用自 Tornado 4 ...

  2. 深入理解Tornado——一个异步web服务器

    本人的第一次翻译,转载请注明出处:http://www.cnblogs.com/yiwenshengmei/archive/2011/06/08/understanding_tornado.html原 ...

  3. Tornado @tornado.gen.coroutine 与 yield

    在使用 Tornado 的过程中产生了以下疑问: 什么时候需要给函数增加 @tornado.gen.coroutine 什么时候调用函数需要 yield @tornado.gen.coroutine ...

  4. Python之路(四十一):通过项目来深入理解tornado

    Tornado之路   引子 与其感慨路难行,不如马上出发 目录 通过项目来深入理解tornado(一):tornado基础回顾 通过项目来深入理解tornado(二):AsyncHttpClient ...

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

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

  6. 理解tornado

    计算密集型:多进程 IO密集型:多线程   能产生IO阻塞的情况很多,比如网络通讯.磁盘读写.当发生阻塞时,CPU是闲置的,此时如果就一个线程就没法处理其他事情了. 所以对于含有IO阻塞的环境,多线程 ...

  7. tornado.gen.coroutine-协程

    http://blog.csdn.net/seeground/article/details/49488281  

  8. 深入理解yield(三):yield与基于Tornado的异步回调

    转自:http://beginman.cn/python/2015/04/06/yield-via-Tornado/ 作者:BeginMan 版权声明:本文版权归作者所有,欢迎转载,但未经作者同意必须 ...

  9. tornado 杂记

    一.建立一个简单的 hello world 网页 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import tornado.iolo ...

随机推荐

  1. ZooKeeper 之 zkCli.sh客户端的命令使用

    zkCli.sh的使用 ZooKeeper服务器简历客户端 ./zkCli.sh -timeout 0 -r -server ip:port ./zkCli.sh -timeout 5000 -ser ...

  2. pdo 操作

    $dbhost = 'localhost';$dbname = 'dcim';$dbuser = 'dcim';$dbpass = 'dcim'; $locale = "en_US" ...

  3. Linux tomcat自动启动

    1.编辑/etc/rc.d/rc.local 添加环境变量 例如: JAVA_HOME=/usr/local/java/JRE_HOME=/usr/local/java/jreCLASS_PATH=. ...

  4. OK335xS-Android mkmmc-android-ubifs.sh hacking

    #/******************************************************************************* # * OK335xS-Androi ...

  5. C#对文件I/O的一些基本操作

    System.IO命名空间包含允许在数据流和文件上进行同步,异步及写入的类型,下面是关于c#文件的I/O基本操作讲解,需要的朋友可以参考下 文件是一些永久存储及具有特定顺序的字节组成的一个有序的,具有 ...

  6. (4)格式化输出(%用法和format用法以及区别)

    %s用法(%s的用法是写多少个,后面就要传多少个) format用法(基本语法是通过{}和:来代替%.format函数可以接受不限个参数,位置可以不按顺序) 形式一(顺序填坑{}) >>& ...

  7. 【NOI2003】银河英雄传

    迭代不一定比递归好 原题: 公元五八○一年,地球居民迁移至金牛座α第二行星,在那里发表银河联邦创立宣言,同年改元为宇宙历元年,并开始向银河系深处拓展. 宇宙历七九九年,银河系的两大军事集团在巴米利恩星 ...

  8. IEPNGFix 解决IE6支持PNG透明问题

    IE6本身是支持索引色透明度(PNG8)格式,但不支持真彩色透明度(PNG24)格式. 使用IE PNG Fix 2.0可以完美解决IE6支持PNG透明问题,而且支持背景定位和重复属性. IE PNG ...

  9. Nginx 安装成Windows 服务方法

    1. 下载nginx windows版本 http://www.nginx.org 2. 下载微软的2个工具: instsrv.exe.srvany.exe 去微软网站下载安装Windows Serv ...

  10. 作为一名IT从业者,你在工作和学习中,遇到哪些问题

    版权声明:襄阳雷哥的版权声明 https://blog.csdn.net/FansUnion/article/details/28448975 大家都是IT从业者,遇到的问题多少与类似. 假设能把这些 ...