初识tornado

本文介绍了Tornado,一个Python编写的开源异步HTTP服务器和Web框架,以其轻量级和高性能著称。内容包括Tornado的特点、解决C10K问题的能力,以及基础使用如HTTPServer、多进程、tornado.options模块的解析。文章还讨论了Tornado启动多进程的注意事项和日志功能。

初识tornado

  • 什么是tornado

​ 全称 Tornado Web Server , 是一个用Python编写的开源异步HTTP服务器,同时也是一个web开发框架

  • 特点

    1. 作为web框架,是一个轻量级的web框架,其拥有异步非阻塞IO的处理方式
    2. 作为web服务器,Tornado有较为出色的抗负载能力,官方用tornado和其他python web框架做对比,结果最大浏览量超过第二名近40%
  • 使用场景
    1. 用户量大,高并发

    2. 大量得 HTTP 持久连接

      (1) 使用同一个tcp连接来发送和接收多个 HTTP 请求/应答,而不是为每一个新的请求/应答 打开新的连接 得方法

      (2) 对于HTTP 1.0 , 可以在请求头(Header)中添加Connection: Keep-Alive=

      (3) 对于HTTP 1.1 , 所有的连接默认都是持久连接

  • C10K问题

    随着互联网的普及,应用的用户群体几何倍增长,此时服务器性能问题就出现。最初的服务器是基于进程/线程模型。新到来一个TCP连接,就需要分配一个进程。假如有C10K,就需要创建1W个进程,通常用C10K这一概念来描述。即并发10000个连接。

    对于单台服务器来说,根本无法承担。多台服务器分布式又要付出高昂的成本

    tornado 解决C10k问题

    ​ tornado在设计之初就考虑到了性能因素,它的 web server 从底层开始就自己实现了一整套基于 epoll 的单线程异步架构,旨在解决C10K问题


tornado 基础

  • 第一个Tornado代码

    import tornado.web
    #Tornado的基础web框架模块
    import tornado.ioloop
    #Tornado的核心io模块,封装了linux的epoll和BSD的kqueue,是tornado高效的基础
    
    # 处理类(相当于Django中的类视图)
    class IndexHandler(tornado.web.RequestHandler):
        # 路由处理方法(匹配路由后执行)
        def get(self, *args, **kwargs):
            # 一个响应,响应信息
            self.write("sunck is a good man")
    
    if __name__ == '__main__':
        # 创建一个app实例(一个应用)
        # Application:Tornado web的核心类,是与服务器接口对应,里面保存了路由映射表,添加设置,用listen方法创建一个httpf服务器示例,并绑定端口(注意:此时服务器并没有开启监听)
        app = tornado.web.Application([
            (r'/', IndexHandler),
        ])
        #绑定监听的端口,注意:此时也没有开启监听
        app.listen(8000)
        #IOLoop.current() :返回当前线程的IOLoop实例
        #IOLoop.start() :开启IOLoop实例的I/O循环,同时服务器开启监听
        tornado.ioloop.IOLoop.current().start()
    
    
  • Tornado 运行流程

  • httpserver

    HTTPServer在httpserver.py中实现,继承自TCPServer,是一个无阻塞、单线程HTTP服务器,支持多进程为prefork模式实现

    • httpserver对象
      import tornado.web
      import tornado.ioloop
      
      #引入httpserver模块
      import tornado.httpserver
      
      class IndexHandler(tornado.web.RequestHandler):
          def get(self, *args, **kwargs):
              self.write("sunck is a good man")
      
      if __name__ == '__main__':
          app = tornado.web.Application([
              (r'/', IndexHandler),
          ])
          # app.listen(8000)
      
          #实例化一个httpserver对象
          httpServer = tornado.httpserver.HTTPServer(app)
          #绑定端口
          httpServer.listen(8000)
      
          tornado.ioloop.IOLoop.current().start()
      
      
    • 单进程与多进程
      1. 默认单进程

      2. 多进程示例:

        import tornado.web
        import tornado.ioloop
        
        # 引入httpserver模块
        import tornado.httpserver
        
        
        class IndexHandler(tornado.web.RequestHandler):
            def get(self, *args, **kwargs):
                self.write("sunck is a good man")
        
        
        if __name__ == '__main__':
            app = tornado.web.Application([
                (r'/', IndexHandler),
            ])
            # app.listen(8000)
        
            # 实例化一个httpserver对象
            httpServer = tornado.httpserver.HTTPServer(app)
            # 绑定端口
            httpServer.bind(8000)
            httpServer.start(0)
        
            tornado.ioloop.IOLoop.current().start()
        
        
      3. 补充说明:

        httpServer.bind(port): 给服务器绑定端口

        httpServer.start(num_processes):

        ​ (1) 开启指定个数的进程数据,默认值为1,开启1个进程

        ​ (2) 值为None或者小于等于0,则根据机器硬件的CPU核心数创建相同数目的子进程

        ​ (3) 值大于0,则创建对应个数个子进程

        Tornado提供了一次性开启多个进程的方法,但是会存在一些问题,所以不建议使用httpServer.start()方法。一般手动开启多个进程并绑定不同的端口号

        问题:

        (1) 每个子进程都给拷贝一份父进程中的数据(IOLoop实例),如果修改了IOLoop,其他子进程也会受到影响

        (2) 所有的进程是由一个命令一次开启,无法做到不暂定服务情况下修改更新代码

        (3) 所有进程共享一个端口

  • tornado.options

    Tornado提供了一个tornado.options模块,用来定义全局参数,并存储外部传入的参数,转换参数

    基础属性和方法
    • tornado.options.define() (方法)

      原型:

      tornado.options.define(name,default=None,type=None,help=None,metavar=None,multiple=False,group=None,callback=None)
      

      功能:

      ​ 用来定义options选项变量的方法

      参数:

      ​ name:选项变量名。注意:必须保证全局唯一性,否则会报“Option ‘xxx’ already defined in xxx”

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

      ​ type: 选项变量的类型,从命令行或者配置文件导入参数时,Tornado会根据数据的值自动配置类型。 可以str、int、float、datetime、timedita类型中的任意一个,如果没有设置,会根据defaultd 值自动推导,如果default没有设置,不会自动推导。

      ​ multiple: 选项变量的值是否可以有多个,默认为False。如果为True,传用逗号隔开,而接受的选项变量 则为一个list

      ​ help: 选项变量的帮助信息(需要在代码中加入tornado.options.parse_command_line())

    • tornado.options.options (属性)

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

    • tornado.options.parse_command_line()

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

      示例:

      import tornado.web
      import tornado.ioloop
      import tornado.options
      
      tornado.options.define("port",default=8000,type=int,help="this is port",multiple=False)
      tornado.options.define("list",default=[],type=str,help="this is port",multiple=True)
      
      class IndexHandler(tornado.web.RequestHandler):
          def get(self, *args, **kwargs):
              self.write("sunck is a good man")
      if __name__ == '__main__':
          tornado.options.parse_command_line()
          app = tornado.web.Application([
              (r'/', IndexHandler),
          ])
          print(tornado.options.options.list)
          app.listen(tornado.options.options.port)
          tornado.ioloop.IOLoop.current().start()
      

      黑屏终端启动:python server.py --port=8000 --list=good,nice,handsome

    • tornado.options.parse_config_file(path)

      作用:从配置文件导入options

      server示例:

      import tornado.web
      import tornado.ioloop
      import tornado.options
      
      tornado.options.define("port",default=8000,type=int,help="this is port",multiple=False)
      tornado.options.define("list",default=[],type=str,help="this is port",multiple=True)
      
      class IndexHandler(tornado.web.RequestHandler):
          def get(self, *args, **kwargs):
              self.write("sunck is a good man")
      if __name__ == '__main__':
          tornado.options.parse_config_file("./config")
          app = tornado.web.Application([
              (r'/', IndexHandler),
          ])
          print(tornado.options.options.list)
          app.listen(tornado.options.options.port)
          tornado.ioloop.IOLoop.current().start()
      

      config示例:

      port = 9000
      list = ["good","nice","handsome"]
      

      说明:

      ​ 此时配置文件的书写格式仍然需要安装python的语法来写,优点是可以将配置文件存储到全局options对象中,但是,不利于在代码中来调用define()函数定义选项,而且不支持字典类型。这种方式以后很少用。


      config.py配置方式:

      在使用配置文件时,一般创建一个新的python文件(config.py),在该文件中直接定义python数据类型(一般使用字典类型),在需要配置文件参数的地方,将config.py作为模块导入,再使用其中的变量值

      server示例:

      import tornado.web
      import tornado.ioloop
      
      import config
      
      class IndexHandler(tornado.web.RequestHandler):
          def get(self, *args, **kwargs):
              self.write("sunck is a good man")
      if __name__ == '__main__':
          app = tornado.web.Application([
              (r'/', IndexHandler),
          ], **config.settings)
          print(config.options["list"])
          app.listen(config.options["port"])
          tornado.ioloop.IOLoop.current().start()
      
      

      config.py示例:

      
      options = {
          "port": 9000,
          "list": ["good", "nice", "handsome"],
      }
      
  • 日志

    当我们在代码中调用parse_command_file()或者parse_config_file(),Tornado会默认开启logging模块功能,即开启日志功能(向屏幕打印信息)

    关闭日志:

    1. python server04.py --port=9000 --logging=none
    2. tornado.options.options.logging = None (转换参数前)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值