tornado.gen.coroutine 使用初识

准备使用 tornado 4.0 开发业务服务.
目前有一个场景, 即客户端发送一个 auth post请求过来, 但服务器属于边缘节点,
需要把 auth 转发到真正的后台服务器.
此时有两种方式发送:
1. 边缘节点在接收到 post 请求, 然后调用 tornado.httpclient.HTTPClient()
同步获得结果 response
2. 异步方式操作, 不影响其他用户的请求(即不阻塞进程)
在阅读 tornado demo 的 authdemo.py 源码时 有一个 @gen.coroutine 使用
于是查阅相关资料, 并做了代码验证.

模仿边缘节点的测试代码

本地 nginx定义了 url “/async” 路径, 当访问 “http://127.0.0.1:80/async”时,
nginx加载自己定义的Lua脚本, Lua脚本调用shell命令 sleep, 进程会阻塞 5秒,
再返回给边缘节点结果.

nginx 的 test_async.conf 文件定义(入口配置文件 nginx.conf 会 include 该配置):

在 /mynginx/luapath/app/ 路径下放置了Lua脚本, test_async.lua:

开启 Nginx服务器后,现在我们开始测试
测试: 打开两个终端, 先执行test1, 后test2: (保证在5秒内操作两个步骤)

test1 脚本:

test2脚本:

tornado服务器调试 print 输出结果:
null

实验证明, 先发送 /async url 请求, 再 转发到 nginx 获取最后结果过程中,
tornaodo 服务并不阻塞其他用户的请求. 即先执行完成的是 GetBaiduHandler
的结果,其次才是 “/async”的 nginx 服务延时返回给tornado后转发的结果.

查阅其他博客发现在 @gen.coroutine 之前添加一个 decorator:
@tornado.web.asynchronous
但这是不必要的, 根据文档描述

This decorator is unnecessary if the method is also decorated with
@gen.coroutine (it is legal but unnecessary to use the two
decorators together, in which case @asynchronous must be
first).

如果不使用 @gen.coroutine, 而使用 @tornado.web.asynchronous,
那么重新实现一个例子的Handler:

  • 使用 @tornado.web.asynchronous 在代码描述上类似于 Node.js
    这里通过设置 _on_response 回调函数.
  • tornado 的 tornado.gen.coroutine 方便在于, 少定义一个回调函数,
    以顺序代码的方式(里面有 yield 进程挂起) 书写代码.
  • Node.js 因其底层执行的 C/C++代码处理了大量的工作, 而在 js语法上
    使用大量的回调(当然也有很好的库帮助开发者顺序执行代码).

在初步使用tornado gen.coroutine时, 现在认为在可以使用异步
又可以使用顺序执行的场景:
阅读七牛的文档后, 假设要模仿其 http 请求的结构做简单的上传服务,
会有如下步骤:
1. 上传文件前首先做验证, 这需要异步请求其他服务器,
而获得数据后将验证结果存放本地(缓存).
2. 在之后上传文件只需接收到文件流, 每个 http 请求的验证
只需读取本地信息(缓存)即可,而此时是没必要使用异步的方式实现的,
存储临时文件在本地服务器的写文件操作不是阻塞的.

使用 Python 的一个可能劣势, 当执行速度遇到瓶颈(大量的用户上传到
同一台服务器时), 脚本执行速度是需要提高的, 如果需要, 那么用 C/C++
重写服务就会是优化项了, 而且还要 实现在验证步骤的异步消息机制.

原创文章,转载请注明: 转载自kaka_ace's blog

本文链接地址: tornado.gen.coroutine 使用初识

发表评论

电子邮件地址不会被公开。 必填项已用*标注