异步框架-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和body
  • RequestHandler.get_query_argument()>Optional[str] 获取指定name的query params
  • RequestHandler.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(优势)、

框架性能

运行部署

全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务