初识tornado
全称 Tornado Web Server , 是一个用Python编写的开源异步HTTP服务器,同时也是一个web开发框架
-
特点
- 作为web框架,是一个轻量级的web框架,其拥有异步非阻塞IO的处理方式
- 作为web服务器,Tornado有较为出色的抗负载能力,官方用tornado和其他python web框架做对比,结果最大浏览量超过第二名近40%
-
使用场景
-
用户量大,高并发
-
大量得 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() -
单进程与多进程
-
默认单进程
-
多进程示例:
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() -
补充说明:
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模块功能,即开启日志功能(向屏幕打印信息)
关闭日志:
- python server04.py --port=9000 --logging=none
- tornado.options.options.logging = None (转换参数前)
本文介绍了Tornado,一个Python编写的开源异步HTTP服务器和Web框架,以其轻量级和高性能著称。内容包括Tornado的特点、解决C10K问题的能力,以及基础使用如HTTPServer、多进程、tornado.options模块的解析。文章还讨论了Tornado启动多进程的注意事项和日志功能。

2828

被折叠的 条评论
为什么被折叠?



