【网站构建】Python高性能架构Tornado

志扬工作室

共 9904字,需浏览 20分钟

 ·

2021-06-27 11:29

Start:关注本公众号后,可直接联系后台获取排版美化的详细文档!

Hints:本篇文章所编纂的资料均来自网络,特此感谢参与奉献的有关人员。


  • Tornado的简单概述:

Tornado是一个基于PythonWeb服务框架和异步网络库。Tornado 是一个基于PythonWeb服务框架和异步网络库。由facebook开源出来的超高并发框架,利用异步协程机制,实现比多线程更高的性能爆发,绝对是高并发类网站的首选,知乎网就是用这个框架开发的,性能超高。

 

  • Tornado的应用场景:

-1用户量大,高并发

如秒杀抢购、双十一某宝购物、春节抢火车票

-2大量的HTTP持久连接

使用同一个TCP连接来发送和接收多个HTTP请求/应答,而不是为每一个新的请求/应答打开新的连接的方法。对于HTTP 1.0,可以在请求的包头(Header)中添加Connection: Keep-Alive。对于HTTP 1.1,所有的连接默认都是持久连接。

 

  • Tornado的主要构成:

-Web 框架 (包括用来创建 Web 应用程序的 RequestHandler, 还有很多其它支持的类).

-HTTP 客户端和服务器的实现 (HTTPServer AsyncHTTPClient).

-异步网络库 (IOLoop IOStream), HTTP 的实现提供构建模块, 还可以用来实现其他协议.

-协程库 (tornado.gen)让用户通过更直接的方法来实现异步编程, 而不是通过回调的方式.
Tornado web 框架和 HTTP 服务器提供了一整套WSGI的方案.可以让Tornado编写的Web框架运行在一个WSGI容器中 (WSGIAdapter),或者使用 TornadoHTTP 服务器作为一个WSGI容器 (WSGIContainer),这两种解决方案都有各自的局限性, 为了充分享受Tornado为您带来的特性,你需要同时使用Tornadoweb框架和HTTP服务器.

 

  • Tornado的关键概念:

异步和非阻塞 I/O

实时的web特性通常需要为每个用户一个大部分时间都处于空闲的长连接.在传统的同步web服务器中,这意味着需要给每个用户分配一个专用的线程,这样的开销是十分巨大的.为了减小对于并发连接需要的开销,Tornado使用了一种单线程事件循环的方式.这意味着所有应用程序代码都应该是异步和非阻塞的,因为在同一时刻只有一个操作是有效的.

-阻塞

一个函数通常在它等待返回值的时候被阻塞 .一个函数被阻塞可能由于很多原因:网络I/O,磁盘I/O,互斥锁等等.事实上, 每一个函数都会被阻塞,只是时间会比较短而已。

-异步

一个异步 函数在它结束前就已经返回了,而且通常会在程序中触发一些动作然后在后台执行一些任务.(和正常的同步 函数相比, 同步函数在返回之前做完了所有的事).

-协程

Tornado 中推荐用 协程 来编写异步代码. 协程使用 Python 中的关键字 yield来替代链式回调来实现挂起和继续程序的执行。协程和异步编程的代码一样简单, 而且不用浪费额外的线程. 它们还可以减少上下文切换让并发更简单.

 

  • Tornado的环境配置:

Pip install tornado

 

  • Tornado的HelloWorld

import tornado.ioloop
import tornado.web
# handler类,它代表着业务逻辑,我们进行服务端开发时就是编写一堆一堆的handler用来服务客户端请求。
class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello,world")
def make_app():
    return tornado.web.Application(
        # 路由表,它将指定的url规则和handler挂接起来,形成一个路由映射表。当请求到来时,根据请求的访问url查询路由映射表来找到相应的业务handler
        [
            (r"/", MainHandler),
        ]
    )
if __name__ == "__main__":
    # app实例,它代表着一个完成的后端app,它会挂接一个服务端套接字端口对外提供服务。
    app = make_app()
    # 后端app监听端口设置
    app.listen(8888)
    # ioloop实例,全局的tornado事件循环
    tornado.ioloop.IOLoop.current().start()

一个普通的tornado web服务器通常由四大组件组成。

-1.ioloop实例,它是全局的tornado事件循环,是服务器的引擎核心,示例中tornado.ioloop.IOLoop.current()就是默认的tornado ioloop实例。

-2.app实例,它代表着一个完成的后端app,它会挂接一个服务端套接字端口对外提供服务。一个ioloop实例里面可以有多个app实例,示例中只有1个,实际上可以允许多个,不过一般几乎不会使用多个。

-3.handler类,它代表着业务逻辑,我们进行服务端开发时就是编写一堆一堆的handler用来服务客户端请求。

-4.路由表,它将指定的url规则和handler挂接起来,形成一个路由映射表。当请求到来时,根据请求的访问url查询路由映射表来找到相应的业务handler

这四大组件的关系是,一个ioloop包含多个app(管理多个服务端口),一个app包含一个路由表,一个路由表包含多个handlerioloop是服务的引擎核心,它是发动机,负责接收和响应客户端请求,负责驱动业务handler的运行,负责服务器内部定时任务的执行。

当一个请求到来时,ioloop读取这个请求解包成一个http请求对象,找到该套接字上对应app的路由表,通过请求对象的url查询路由表中挂接的handler,然后执行handlerhandler方法执行后一般会返回一个对象,ioloop负责将对象包装成http响应对象序列化发送给客户端。

 

  • Tornado的Redis使用

import json

import redis

import tornado.ioloop

import tornado.web

 

class FactorialService(object):

 

   def __init__(self):

       self.cache = redis.StrictRedis("localhost", 6379)  # 缓存换成redis

       self.key = "factorials"

 

   def calc(self, n):

       s = self.cache.hget(self.key, str(n)) # hash结构保存计算结果

       if s:

           return int(s), True

       s = 1

       for i in range(1, n):

           s *= i

       self.cache.hset(self.key, str(n), str(s))  # 保存结果

       return s, False

 

 

classFactorialHandler(tornado.web.RequestHandler):

 

   service = FactorialService()

 

   def get(self):

       n = int(self.get_argument("n") or 1)  # 参数默认值

       fact, cached = self.service.calc(n)

       result = {

           "n": n,

           "fact": fact,

           "cached": cached

       }

       self.set_header("Content-Type", "application/json;charset=UTF-8")

       self.write(json.dumps(result))

 

 

def make_app():

   return tornado.web.Application([

       (r"/fact", FactorialHandler),

   ])

 

if __name__ == "__main__":

   app = make_app()

   app.listen(8888)

   tornado.ioloop.IOLoop.current().start()

 

当我们再次访问http://localhost:8888/fact?n=50,可以看到浏览器输出如下
{"cached": false, "fact":608281864034267560872252163321295376887552831379210240000000000, "n":50}
,再刷新一下,浏览器输出{"cached": true, "fact":608281864034267560872252163321295376887552831379210240000000000, "n":50},可以看到cached字段由true编程了false,表明缓存确实已经保存了计算的结果。我们重启一下进程,
再次访问这个连接,观察浏览器输出,可以发现结果的cached依旧等于true。说明缓存结果不再是存在本地内存中了。


  • Tornado的项目结构:

备注:手工创建上述的文件夹及文件

-application.py

全局环境设置,包括静态目录设置、模板目录设置、是否debug,及可能需要用到的cookies加密设置

-server.py

启动tornado服务主文件,主要包括web的访问URL及端口配置

url.py

URL路由,即用来配置访问某个URL路径时,该具体定位到哪个HTML文件

handles 文件夹

用来具体处理网页动态交互请求,里面主要是getpost方法中的逻辑开发。

Handlers文件夹下的index.py

存放对应的Handlers类响应请求

statics 文件夹

用来存放网页需要的CSS样式表文件、Javascript文件及图片、视频等静态网页内容,这个文件夹的特征是,通过浏览器URL路径可直接访问,所以不要存放需要保密的后台程序文件

templates 文件夹

用来存放静态HTML文件。

1. tornado.web

tornado的基础web框架模块

RequestHandler

封装了对应一个请求的所有信息和方法,write(响应信息)就是写响应信息的一个方法;对应每一种http请求方式(get、post等),把对应的处理逻辑写进同名的成员方法中(如对应get请求方式,就将对应的处理逻辑写在get()方法中),当没有对应请求方式的成员方法时,会返回“405: Method Not Allowed”错误。

Application

Tornado Web框架的核心应用类,是与服务器对接的接口,里面保存了路由信息表,其初始化接收的第一个参数就是一个路由信息映射元组的列表;其listen(端口)方法用来创建一个http服务器实例,并绑定到给定端口(注意:此时服务器并未开启监听)。

2. tornado.ioloop

tornado的核心io循环模块,封装了Linux的epoll和BSD的kqueue,tornado高性能的基石。以Linux的epoll为例,其原理如下图:

 

 

IOLoop.current()

返回当前线程的IOLoop实例。

IOLoop.start()

启动IOLoop实例的I/O循环,同时服务器监听被打开。

总结Tornado Web程序编写思路
创建web应用实例对象,第一个初始化参数为路由映射列表。
定义实现路由映射列表中的handler类。
创建服务器实例,绑定服务器端口。
启动当前线程的IOLoop。

3 httpserver
上一节我们说在tornado.web.Application.listen()(示例代码中的app.listen(8000))的方法中,创建了一个http服务器示例并绑定到给定端口


  • Tornado的常用操作:

-options

tornado.options模块——全局参数定义、存储、转换。

tornado.options.define()

用来定义options选项变量的方法,定义的变量可以在全局的tornado.options.options中获取使用,传入参数:

name 选项变量名,须保证全局唯一性,否则会报“Option'xxx' already defined in ...”的错误;

default 选项变量的默认值,如不传默认为None

type 选项变量的类型,从命令行或配置文件导入参数的时候tornado会根据这个类型转换输入的值,转换不成功时会报错,可以是strfloatintdatetimetimedelta中的某个,若未设置则根据default的值自动推断,若default也未设置,那么不再进行转换。可以通过利用设置type类型字段来过滤不正确的输入。

multiple 选项变量的值是否可以为多个,布尔类型,默认值为False,如果multipleTrue,那么设置选项变量时值与值之间用英文逗号分隔,而选项变量则是一个list列表(若默认值和输入均未设置,则为空列表[])。

help 选项变量的帮助提示信息,在命令行启动tornado时,通过加入命令行参数--help 可以查看所有选项变量的信息(注意,代码中需要加入tornado.options.parse_command_line())。

tornado.options.options

全局的options对象,所有定义的选项变量都会作为该对象的属性。

tornado.options.parse_command_line()

转换命令行参数,并将转换后的值对应的设置到全局options对象相关属性上。

-日志

当我们在代码中调用parse_command_line()或者parse_config_file()的方法时,tornado会默认为我们配置标准logging模块,即默认开启了日志功能,并向标准输出(屏幕)打印日志信息。

如果想关闭tornado默认的日志功能,可以在命令行中添加--logging=none 或者在代码中执行如下操作:

from tornado.options import options, parse_command_line

options.logging= None

parse_command_line()


  • Tornado的常用模块:

  • Web framework:

   tornado.web — RequestHandler and Application classes

   tornado.template - 模板

   tornado.routing - 基本路由实现

   tornado.escape - 转义和字符串操作

   tornado.locale - 国际化支持

   tornado.websocket - 与浏览器的双向通信socket

  • tornado的HTTP服务器和客户端:

    tornado.httpserver- 非阻塞HTTP服务器

   tornado.httpclient - 异步HTTP客户端

   tornado.httputil - 操纵HTTP头和URL

   tornado.http1connection - HTTP / 1.x客户端/服务器实现

  • 异步网络:

   tornado.ioloop -主事件循环

   tornado.iostream - Flexible output generation(灵活的输出生成

   tornado.netutil - 操作HTTP报头和URL的工具类

   tornado.tcpclient- IOStream连接工厂

   tornado.tcpserver- IOStream基于TCP的服务器

  • 协程和并发

   tornado.gen - 基于发生器的协程

   tornado.locks - 同步原语

   tornado.queues - 协程队列

   tornado.process - 用于多个进程的实用程序

  • 与其他服务集成

   tornado.auth - 使用OpenIDOAuth进行第三方登录

   tornado.wsgi - 与其他Python框架和Web服务器的网关接口

   tornado.platform.caresresolver - 使用C-Ares的异步DNS解析器

   tornado.platform.twisted - twistedtornado之间的桥梁

   tornado.platform.asyncio- asynciotornado之间的桥梁

  • Utilities

   tornado.autoreload - 自动检测开发中的代码更改

   tornado.concurrent-  Work withFuture objects

   tornado.log - 打印日志的

   tornado.options - 命令行解析

   tornado.stack_context - 跨异步回调的异常处理

   tornado.testing - 对异步代码的单元测试支持

   tornado.util - 通用工具类

 

  • 参考链接:

Tornado简介:

https://blog.csdn.net/Ka_Ka314/article/details/81163740

Tornado的项目架构:

https://zhuanlan.zhihu.com/p/127922316

Tornado+Redis

https://zhuanlan.zhihu.com/p/37382503

Tornado简易教程

https://blog.csdn.net/belalds/article/details/80575755

Tornado开发教程

https://www.cnblogs.com/jiangxiaobo/p/12776283.html

用 gunicorn + gevent 跑 tornado app

https://zhuanlan.zhihu.com/p/31635068

Tornado手册

http://www.ttlsa.com/docs/tornado/#overview

Tornado官网

https://www.tornadoweb.org/en/stable/

Tornado的前后端

https://www.cnblogs.com/xiaobeibei26/p/6646083.html

公众号二维码

End:如果有兴趣了解金融量化交易和其他数据分析的实用技术,欢迎关注本公众号

浏览 52
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报