异步框架-tornado核心详解
简单介绍
Tornado是一个Python web异步框架,通过使用非阻塞网络I/O,可支撑上万连接。选择使用tornado框架的开发者大部分是因为tornado优秀的异步并发特性可以满足其高并发异步的需求。
那么我们需要理解两个概念:同步阻塞和异步非阻塞。
- 同步阻塞:A、B两家人共用一个灶,A家用完灶之后,B家才能开始做饭。
- 异步非阻塞:王阿姨做饭,电饭锅煮上饭之后就去炖汤,饭煮好后电饭锅发出滴滴声再去盛饭。
显而易见,异步非阻塞模式更加高效,tornado支持异步非阻塞,高并发长连接Http服务使用tornado框架是个很好的选择。
Web框架
tornado web框架可以快速搭Restful APi服务,支持GET、POST、PUT、DELET、PATCH方法。tornado.web提供了一个具有异步特征的web框架,能支持10k+连以及长轮询。
以下是一个简单tornado HTTP服务示例。
import tornado.ioloop
import tornado.web
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, world")
def make_app():
return tornado.web.Application([
(r"/", MainHandler),
])
if __name__ == "__main__":
app = make_app()
app.listen(8080)
tornado.ioloop.IOLoop.current().start()RequestHandler
tornado web应用基本都是通过RequestHandler类内的方法完成,RequestHandle内跟HTTP方法同名的函数处理对应HTTP方法的请求
线程安全说明
一般情况下, 在 RequestHandler 中的方法和Tornado中其他的方法不是线程安全的。 如write(),finish(),和flush()这些方法只能从主线程调用。如果你使用多线程, 那么在结束请求之前, 使用IOLoop.add_callback来把控制权传送回主线程是很重要的。
Entry points
RequestHandler除了get()、post()等一些HTTP方法外还有一些空函数,主要用于必要时重写子类从而重定义内容。函数处理HTTP请求的调用顺序如下:
RequestHandler.initialize(),对应旧版本的init。如果URL配置的第三个参数,是dict的话,会传到initialize() 方法里。
class UserHandler(RequestHandler): def initialize(self, database): self.id = id def get(self, username): ... app = Application([ (r'/user_info/(.*)', UserHandler, dict(id=id)), ])RequestHandler.prepare(),在处理请求前执行。对于一些有访问前限制需求,我们可以重写此方法实现。
class UserHandler(RequestHandler): def prepare(self): if self.request.headers["Content-Type"].startswith("application/json"): self.json_args = json.loads(self.request.body) else: self.json_args = {}RequestHandler.on_finish(),请求逻辑处理后执行。通过重写这个方法做清理操作。
class UserHandler(RequestHandler): def on_finish(self): print("request finish operation")Input&Output
通过以下简单例子了解tornado的输入与输出。
# -*- coding: utf-8 -*-
import json
import tornado.web
from webob.multidict import MultiDict
import wtforms
from wtforms import validators
class ChannelForm(wtforms.Form):
channel = wtforms.StringField(validators=[validators.DataRequired()])
class BaseHandler(tornado.web.RequestHandler):
def set_default_headers(self):
"""设置头部信息"""
self.set_header('Content-Type', 'application/json')
def write_json(self, data, status=200):
"""自定义返回信息格式、状态码"""
self.set_status(status)
self.write(json.dumps(data, ensure_ascii=False))
class ChannelHandler(BaseHandler):
async def post(self):
# Input:self.request.body,客户端所传参数
# 验证表单参数
form = ChannelForm(json.loads(self.request.body))
if form.validate():
# 创建渠道记录操作
...
print("Creat channel successfully!!")
# Output: 返回输出信息
self.write_json("Creat channel successfully!!", 400)
else:
self.write_json(form.errors, 400)
self.finish()request.body,获取body中参数,通过json以后就可以直接取值ChannelForm,参数校验set_default_headers,设置头部信息write_json,输出返回信息给客户端
`Input和Output方式多种,详细信息如下:
input
tornado获取参数方法支持表单、json等格式,以下是常用获取参数的方法。
RequestHandler.get_argument()>Optional[str]获取指定name的query params和body的参数。RequestHandler.get_arguments()->List[str]返回指定name的参数列表,包括query params和bodyRequestHandler.get_query_argument()>Optional[str]获取指定name的query paramsRequestHandler.get_query_arguments()->List[str]获取指定name的query参数列表RequestHandler.get_body_argument()->Optional[str]获取指定name的body参数RequestHandler.get_body_arguments()->List[str]获取指定name的body参数列表
Output
开发者可以通过以下函数自定义设置返回状态码、头部信息等。
RequestHandler.set_status(status_code: int, reason: str = None)设置返回状态码RequestHandler.set_header(name: str, value: Union[bytes, str, int, numbers.Integral, datetime.datetime])设置头部信息RequestHandler.finish(chunk: Union[str, bytes, dict] = None) → Future[None]结束http请求RequestHandler.redirect(url: str, permanent: bool = False, status: int = None) → None重定向RequestHandler.render(template_name: str, **kwargs) → Future[None]返回模板。调用此方法后调用其他方法失效,原因是调用这个函数时会调用finish方法。
注意:self.finish()并不意味着请求返回结束,它后续的逻辑还可以继续执行,如果要你要终结逻辑,需要在self.finish()后添加return
Application 类
Application类组成一个了web应用程序的请求处理程序的集合,可被调用并且作为应用程序传递给HTTPServer。构造器内列表包含URLSpec对象,按顺序执行路由对应第一个请求类。
简单示例如下:
application = web.Application([
(r"/", MainPageHandler),
])
http_server = httpserver.HTTPServer(application)
http_server.listen(8080)
ioloop.IOLoop.current().start()settings
传递给Application的关键字参数会保存于settings中,我们就可以通过重写RequestHandler子类的方式或者写入settings的方式自定义配置。settings配置如下:
- 基础设置,debug、cookie_secret、login_url等系统参数基础设置。
- 模板设置,template_pat、template_loader等web框架模板相关设置。
- 静态文件设置,static_path、static_url_prefix等静态文件相关配置。
(下)
异步并发
异步并发原理、epoll(优势)、
查看18道真题和解析