快速构建高性能web框架Tornado的基础结构

Posted by Naah on Friday, Jun 28,2019 21:17:24

1 介绍

大部分python开发都知道Flask,Djongo,Tornado.

而我在进行python端的web开发时,会根据所实现的功能进行技术选型.因为我目前所从事的算法工程化方向,我一般都会采用Tornado进行web开发.下面呢就说说我为什么选择使用Tornado.

Tornado的优点和缺点都很明显,下面我们来列举下:

优点:

天生异步(采用epoll作为并发模型),在处理http请求上性能爆表,配合uvloop作为事件循环,更是锦上添花,轻量级的web框架.

缺点:

生态不够完整,组件不够丰富,在传统web开发时,开发效率较慢.

但是在我所从事的算法工程化方向,不像传统的web开发,比如需要连接数据库,使用mq等相关功能.我们要做的是把算法的能力暴露出去,提供最快的服务访问能力.

而且在python生态上微服务生态基本等于0的,我们可以基于tornado自己构建一套公司的微服务组件.

下面我们就用代码来构建我们的tornado环境.

2 环境构建

我目前所用的环境是Python3.6.8 在这里,我就不介绍关于pipconda的相关知识啦! 使用conda安装下面的依赖!

tornado==6.0.2
uvloop==0.12.2
simplejson==3.16.0

3 代码实现

本文代码已上传至github

3.1 TornadoUvloopConfiguration

这个类用来配置uvloop的

import asyncio
import logging

import uvloop
from tornado.platform.asyncio import BaseAsyncIOLoop

logger = logging.getLogger(__name__)
class TornadoUvloopConfiguration(BaseAsyncIOLoop):

    def initialize(self, **kwargs):
        logger.info("uvloop will init ")
        asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
        loop = uvloop.new_event_loop()
        try:
            super(TornadoUvloopConfiguration, self).initialize(
                loop, close_loop=True, **kwargs)
        except Exception:
            loop.close()
            raise

3.2 TornadoUVloopHttpServer

这个单例类是我们来实现Tornado HTTP Server.

可以通过参数来设置端口和多进程启动

import logging

import tornado.web
from tornado.httpserver import HTTPServer

from configuration.uvloop_configuration import TornadoUvloopConfiguration

logger = logging.getLogger(__name__)


class TornadoUVloopHttpServer(object):
    _instance = None

    __http_server = None

    @staticmethod
    def get_instance(app: tornado.web.Application, port: int, process_num: int = 1):
        """
        singleton class
        :param app: tornado app
        :param port: server port
        :param process_num: multi-process num,default 1
        :return:
        """
        return TornadoUVloopHttpServer(app, port, process_num)

    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super(TornadoUVloopHttpServer, cls).__new__(cls)
            cls._instance.__init(args[0], args[1], args[2])
        return cls._instance

    @classmethod
    def __init(cls, app: tornado.web.Application, port: int, process_num: int):
        cls.__http_server = HTTPServer(app)
        cls.__http_server.bind(port)
        cls.__process_num = process_num
        logger.info("http server bind port:%d ,process_num:%d", port, process_num)

    def start(cls):

        tornado.ioloop.IOLoop.configure(TornadoUvloopConfiguration)
        cls.__http_server.start(cls.__process_num)
        tornado.ioloop.IOLoop.current().start()

3.3 HelloHandler

这个handler是我们用来进行测试的

from tornado import gen
from tornado.web import RequestHandler

class HelloHandler(RequestHandler):
    # 协程装饰器
    @gen.coroutine
    def get(self):
        self.write("Hello, world")

3.4 Main

启动类,并且注册handler

from tornado.web import Application
from common.http_server import TornadoUVloopHttpServer
from handler.hello_handler import HelloHandler

class Main(Application):
    def __init__(self, **settings):
        super(Main, self).__init__([("/", HelloHandler)], **settings)

if __name__ == '__main__':
    TornadoUVloopHttpServer.get_instance(Main(), 6969).start()

4 运行

运行Main.py后,我们打开浏览器访问127.0.0.1:6969,看到下面的图片,就说明成功啦!