Tornado开发技巧,简单了解tornado
tornado基础入门(一)——简单了解tornado
参考:http://demo.pythoner.com/itt2zh/ch1.html
tornado是一个轻量级的web框架,是一个用python写的web服务器,它有三个最大的特点(优势)速度、简单和可扩展性。
编写tornado应用做多最多的工作就是定义一个类去继承tornado中的RequestHandler类。
来看一个例子:
# hello.py

1 import tornado.httpserver
2 import tornado.ioloop
3 import tornado.options
4 import tornado.web
5
6 from tornado.options import define, options
7 define("port", default=8000, help="run on the given port", type=int)
8
9 class IndexHandler(tornado.web.RequestHandler):
10 def get(self):
11 greeting = self.get_argument('greeting', 'Hello')
12 self.write(greeting + ', friendly user!')
13
14 if __name__ == "__main__":
15 tornado.options.parse_command_line()
16 app = tornado.web.Application(handlers=[(r"/", IndexHandler)])
17 http_server = tornado.httpserver.HTTPServer(app)
18 http_server.listen(options.port)
19 tornado.ioloop.IOLoop.instance().start()

这个例子编写了一个非常简单的应用。
我们可以在命令行中启动它:
python hello.py --port=8000
然后再从浏览器中打开这个应用,输入网址:
http://localhost:8000/
可以看到网页上显示:
Hello, friendly user!
" 我们在命令行输入的 ’prot' 的参数是通过第七行中的define传递的,define是tornado.options模块中的一个函数,这个模块用来读取命令行中的一些设置。例如我们在命令行中设置了它的端口prot=8888,define就匹配出它所设置的同名变量 ‘prot’ ,将它从默认值改为 ‘8888’(默认值为8000),这时我们则需要从这个网址进入“http://localhost:8888/" "
这显示的是我们代码第12行 ’write‘进的内容。
我们可以定制一下这个内容,可以看到 ’write' 的有个自定义的变量 ‘greeting' ,而这个变量的默认值为 'Hello’ , 它是通过tornado中的内建函数 ‘ get_argument ‘ 来传递给 ’write‘ ,
所以我们来改变这个变量,从哪入手呢? 从网址入手!
http://localhost:8000/?greeting=Hi
在 ‘?’后给变量重新赋值,这时可以发现网页上的内容变为:
Hi, friendly user!
来梳理以下这段代码的工作流程:

14 if __name__ == "__main__": 15 tornado.options.parse_command_line() 16 app = tornado.web.Application(handlers=[(r"/", IndexHandler)]) 17 http_server = tornado.httpserver.HTTPServer(app) 18 http_server.listen(options.port) 19 tornado.ioloop.IOLoop.instance().start()

1. 我们的应用真正运行起来的时 ‘15、16 ’两行,通过tornado.options模块解析命令行参数,再创建了一个tornado的Application类的实例,最重要的参数时 ‘handler’ 它来告诉tornado应该用哪个类来响应请求。
2. 后面开始,这段代码将会被反复使用,Application对象被创建,我们将其传递给tornado中的HTTPServer对象,然后使用我的命令行指定端口监听(通过options模块取出)。
3. 最后,程序准备好接受http请求后,我们创建一个tornado的IOLoop的实例。
Tornado开发技巧
Tornado框架算是很轻量级的 单线程 异步 编程框架,只是额外加了很基础的模板、HEADER、COOKIE、路由等的WEB相关的支持(都定义在web.py里),它的大部分代码是在封装nonblocking socket、epoll、event loop等基础的异步编程模块。所以,在使用tornado之前一定要先了解这个框架的定位,它不单能够用于WEB服务编程,也非常适用于需要异步编程的后台服务。
tornado框架
Tornado框架的编码水准很高,虽然不了解tornado源码不妨碍使用,但深入了解一下还是有助于提高自己的PYTHON水平的,这里有一份源码详解。

从这个框架图也能看出,tornado 完整地实现了HTTP服务器和客户端,在此基础上提供WEB服务。它可以分为四层:
- 最底层的EVENT层处理IO事件(ioloop.py 和 iostream.py,以及platform相关);
- TCP层实现了TCP服务器,负责数据传输(tcpserver.py);
- HTTP/HTTPS层基于HTTP协议实现了HTTP服务器和客户端(httpserver.py);
- 最上层为WEB框架,包含了模板、认证、本地化等等WEB框架所需的功能(web.py、auth.py、template.py等)。
在TCP层使用tornado,可以从TCPServer派生,但是IO方面需要做进一步处理。示例:
class EchoServer(netutil.TCPServer):
def handle_stream(self, stream, address):
self._stream = stream
self._read_line()
def _read_line(self):
self._stream.read_until('\n', self._handle_read)
def _handle_read(self, data_in):
self._stream.write('You sent: %s' % data_in)
self._read_line()
server = EchoServer()
server.listen(12345)
ioloop.IOLoop.instance().start()
在HTTP/WEB层使用tornado,可以借助Application类,也是我们常用的开发方式。示例:
application = web.Application([
(r"/", MainPageHandler),
])
server = httpserver.HTTPServer(application)
server.listen(8080)
ioloop.IOLoop.current().start()
异步
Tornado虽然是一个异步框架,但是如果使用不当很容易造成性能低下。需要理解一下服务并发量、吞吐量、响应时间这些衡量指标,异步并不能保证这些指标优秀,异步只是指任务不被线性执行。最常见的是如果你在tornado进程里执行一条耗时很长的MySQL查询操作,同样会block住整个tornado进程,而tornado是单线程框架,这意味着block住了该线程上的所有其他请求。
要用好tornado的异步能力,需要掌握内置的异步模块和celery。
web.asynchronous
装饰器 web.asynchronous 只能用在verb函数之前(即get/post/delete等),并且需要搭配tornado异步客户端使用,如httpclient.AsyncHTTPClient。加上这个装饰器后,必须在异步回调函数里显式调用RequestHandler.finish 才会结束这次 HTTP 请求。
tornado里大多的异步函数,包括web.asynchronous都会用到future特性。如果用到了内置的concurrent.Future,需要注意该类不是线程安全的。
gen模块
gen是tornado异步支持的核心模块。
装饰器 gen.coroutine 可以把web.asynchronous装饰的多个分散的异步函数调用写成coroutine的形式,回调函数的结果直接用yield返回。这种用法的优势就不赘述了,目前基本已经在各种主流语言普及了。在版本3.1之后,可以直接省略web.asynchronous改用gen.coroutine替代。
函数 gen.Task 是另外一个在coroutine里使用异步函数的辅助函数,它可以把一个带callback参数的异步调用包装起来,该异步调用传给callback函数的参数将作为yield的返回值。如果传给callback函数的是多参数,会返回一个简单的Argument对象。这里没有cencept定义理解起来可能有些费劲,下面是个示例,运行一遍有助于理解:
import tornado.web
import tornado.gen
import logging
def echo(message, callback):
callback(message, 'that is callback message')
@tornado.gen.coroutine
def test():
response = yield tornado.gen.Task(echo, 'this is first message')
logging.warn(response.args[1])
test()
如果coroutine函数需要返回,需要借助 gen.Return,类似这样: raise tornado.gen.Return(XXX),捕捉这个异常得到返回值。
celery
上面所有的异步调用只使用到了内置的异步客户端httpclient.AsyncHTTPClient,可以参考一下,如果要自己写一个异步客户端还是比较麻烦的。比如,你的函数里包括了一个同步MySQL调用,那么不管你怎么加装饰器,还是yield返回都是没用的,因为你的MySQL调用本身是同步的。可以参考AsyncHTTPClient,借助tornado.ioloop.IOLoop封装一个异步的MySQL客户端,但成本还是很高的。
所幸我们可以借助celery项目,这是一个分布式的任务队列。tornado接到请求后,可以把所有的复杂业务逻辑处理、数据库操作以及IO等各种耗时的同步任务交给celery,由这个任务队列异步处理完后,再返回给tornado。这样只要保证tornado和celery的交互是异步的,那么整个服务是完全异步的。
Tornado和celery的交互可以借助 tcelery 这个适配器。
具体实现可以借助gen模块,这里是个示例:
@tornado.gen.coroutine
def get(self, *args, **kwargs):
response = yield tornado.gen.Task(example_task.apply_async, args=[self.request.arguments])
self.finish(response.result)
上面也说了gen.Task会给传入的example_task.apply_async添加一个callback参数,默认celery的apply_async函数是不认识这个参数的,而tcelery的功能就是对这俩做了适配,让gen.Task和apply_async无缝工作。目前tcelery应该只支持amqp backend。
开发部署
可以使用supervisord启动tornado。1
使用nginx做负载均衡,此时建议给HTTPServer传递参数 xheaders=True。2
调试
开发的时候如果想直接看到改动效果,而不是每次改完还要重新启动python进程,可以借助tornado.autoreload 模块:
python -m tornado.autoreload server.py
同时给Application传递如下参数:
debug=True autoreload=True compiled_template_cache=False static_hash_cache=False serve_traceback=True
对于一些超时的调用直接打印出调用堆栈:
IOLoop.instance().set_blocking_log_threshold(0.050) # 当IOLoop阻塞50ms会打印调用栈
其他
常用工具类
tornado.options
tornado.log 有三个内置的log: access_log、app_log 和 gen_log。
sqlalchemy
tornado里使用sqlalchemy,参考手册 ORM 2.6.9 Contextual/Thread-local Sessions 这一章。保证one session one request即可。
Tornado开发技巧,简单了解tornado的更多相关文章
- tornado基础入门(一)——简单了解tornado
参考:http://demo.pythoner.com/itt2zh/ch1.html tornado是一个轻量级的web框架,是一个用python写的web服务器,它有三个最大的特点(优势)速度.简 ...
- sqlalchemy在pythonweb中开发的使用(基于tornado的基础上)
一.关于SQLAlchemy的安装pip install SQLAlchemy安装如果上面的方式安装不成功的情况可以使用下面的方法 百度下载window或者linux下面对应的sqlalchemy的版 ...
- tornado框架的简单实用
一.安装模块 pip3 install tornado 二.简单的起服务的方法 import json, datetime from tornado.web import RequestHandler ...
- Python+Tornado开发微信公众号
本文已同步到专业技术网站 www.sufaith.com, 该网站专注于前后端开发技术与经验分享, 包含Web开发.Nodejs.Python.Linux.IT资讯等板块. 本教程针对的是已掌握Pyt ...
- Tornado框架的简单使用
一.Tornado Web应用程序的结构 import tornado.web class LoginHandler(tornado.web.RequestHandler): def get(self ...
- tornado 学习笔记5 构建Tornado网站应用
一个Tornado 网站应用通常由一个或多个RequestHanlde的子类.一个负责将请求路由至handlers的Application以及一个启动服务器的main()函数等组成. 一个最小的“he ...
- SQL开发技巧(二)
本系列文章旨在收集在开发过程中遇到的一些常用的SQL语句,然后整理归档,本系列文章基于SQLServer系列,且版本为SQLServer2005及以上-- 文章系列目录 SQL开发技巧(一) SQL开 ...
- 经典收藏 50个jQuery Mobile开发技巧集萃
http://www.cnblogs.com/chu888chu888/archive/2011/11/10/2244181.html 1.Backbone移动实例 这是在Safari中运行的一款Ba ...
- Java 8的五大开发技巧
转载:http://geek.csdn.net/news/detail/94219 在Java 9发布之前,我们来分享一些Java 8开发技巧,本文翻译自JetBrains高级开发主管Trisha G ...
随机推荐
- zabbix agent配置文件记录
一.无论主动还是被动模式都要配置server和linstenPort 二.若要设置主动模式那么要添加ServerActive,若不添加则默认为被动模式
- win7下再装Ubuntu双系统
一.UltraISO制作U盘启动盘 1.1打开 UltraISO,单机“文件”,选择“打开”. 1.2然后单击“启动”,选择“写入硬盘映像”. 二.装Ubuntu 前面省略,直接到安装类型(我的安装好 ...
- priority_queue<int>q;
priority_queue<int>q;//默认不递增q.size();//q中有几个元素q.pop();//删除队首q.top();//返回队首元素q.push();//在队列中插入一 ...
- 005.KVM日常管理2-virt管理
一 安装管理工具 [root@kvm-host ~]# rpm -qa|grep libguestfs-tools #查看相关管理工具,若没安装,可使用yum安装. 二 日常管理 2.1 命令格式 ...
- React Hooks新特性学习随笔
React Hooks 是 React 16.8 的新增特性.它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性. 前言 本篇主要以讲几个常用的api为主. 1.u ...
- Spring重复扫描导致事务失败的解决方案及深入分析
问题及日志使用Spring和mybatis,然后配置事务,出现SqlSession was not registered for synchronization because synchroniza ...
- Web大前端面试题-Day3
1. javascript的typeof返回哪些数据类型? 答案: undefined string boolean number symbol(ES6) Object Function 2. 列举3 ...
- 括弧匹配检验(check.cpp)
[问题描述] 假设表达式中允许包含两种括号:圆括号和方括号,其嵌套的顺序随意,如([ ]())或[([ ][ ])]等为正确的匹配,[( ])或([ ]( )或 ( ( ) ) )均为错 ...
- poj 1797 最短路变形dijkstra
题意:题目大意:有n个城市,m条道路,在每条道路上有一个承载量,现在要求从1到n城市最大承载量,而最大承载量就是从城市1到城市n所有通路上的最大承载量 链接:点我 解题思路:其实这个求最大边可以近似于 ...
- 【BZOJ-2142】礼物 拓展Lucas定理
2142: 礼物 Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 1313 Solved: 541[Submit][Status][Discuss] ...