再次一头扎进Tornado的风暴眼中のイチ
认识Tornado
其实没有啥可说的,和Django一样是一个python web框架,但是轻量化、异步。后来由Facebook收购然后开源出去。
啥?Django是啥?和Tornado一样是一个python web框架,大而全。
Tornado是啥?。。。。。。。
。。。。。。
。。。。。。
。。。。。。
Django大而全,开发敏捷。
Tornado小而精,性能优越。
性能优越的原理
这个epoll啊,然后linux注册,有空闲时间,使用yeild,epoll通知,处理等等等等。。。。
原理复杂的我不想讲(其实还是讲不清楚)。。。。
安装
pip,pip,pip啊少年,我还能说啥
- server.py
# tornado的基础web框架模块import tornado.webimport tornado.ioloop- ``
- ``
# 首页处理类定义# RequestHandler请求处理基础类,处理所有请求的信息和方法class IndexHandler(tornado.web.RequestHandler):# get方式请求# 如果没有定义的请求方法,比如此时是POST方式访问,则或返回405: Method Not Alloweddef get(self):# 返回响应信息的一个方法,Tornado会返回所规定的信息self.write("Hello RedQueen!")- ``
- ``
if __name__ == "__main__":# Application是Tornado Web框架的核心应用类,与服务器对接的接口,# 其中保存路由表,初始化的第一个参数就是路由信息元组/列表app = tornado.web.Application([(r"/", IndexHandler),])# listen方法绑定8000端口创建一个http服务器实例# 此时服务器还未开始监听端口app.listen(8000)# 提示信息print("请访问首页网址http://127.0.0.1:8000")# ioloop是tornado的核心io循环模块,封装了Linux的epoll和BSD的kqueue,tornado高性能的基石。# current返回当前线程的IOLoop实例# start启动IOLoop实例的io循环,此时服务器开始监听端口tornado.ioloop.IOLoop.current().start()
使用python执行文件就可以了
python server.py
之后你会发现程序在打印完提示信息后就停住了,这是你打开浏览器访问提示的网址就会发现神奇的一幕(其实也没啥神奇的,只是说明Tornado开始工作了。)
HTTP服务器
tornado有自己的HTTP服务器实现方法的,这个实现方法不仅能帮助我们理解tornado的启动方式而且有更加丰富的启动选项。
import tornado.webimport tornado.ioloop# tornado 的 http模块import tornado.httpserver- ``
- ``
class IndexHandler(tornado.web.RequestHandler):def get(self):self.write("Hello RedQueen!")- ``
- ``
if __name__ == "__main__":app = tornado.web.Application([(r"/", IndexHandler),])# 创建HTTP服务器实例# 接受应用对象app注册路由映射表http_server = tornado.httpserver.HTTPServer(app)# 将端口监听语句从app.listen(8000)修改为以下语句# 同样的,此时有端口绑定,当时并没有监听http_server.listen(8000)# 提示信息print("请访问首页网址http://127.0.0.1:8000")tornado.ioloop.IOLoop.current().start()
多进程
注意,这里说的是多进程的实现,并不是多线程。
之前的程序实现的都是单进程的实例,如果我们需要用到多进程的实例怎么办呢?
import tornado.webimport tornado.ioloop# tornado 的 http模块import tornado.httpserver- ``
- ``
class IndexHandler(tornado.web.RequestHandler):def get(self):self.write("Hello RedQueen!")- ``
- ``
if __name__ == "__main__":app = tornado.web.Application([(r"/", IndexHandler),])http_server = tornado.httpserver.HTTPServer(app)# 多进程,使用bind进行端口和ip的绑定# app.listen()只能使用在单进程的实例中http_server.bind(8000)# start方法指定开启几个进程,输入参数默认值为1,仅开启一个进程# 如果为None或者小于等于0,则自动根据机器硬件的cpu核芯数创建同等数目的子进程# 如果大于0,则创建与输入参数相同个数的子进程。http_server.start(0)# 提示信息print("请访问首页网址http://127.0.0.1:8000")tornado.ioloop.IOLoop.current().start()
另外:虽然tornado提供了这种开启多进程的方式但是因为:
- 每个子进程会复制一份IOLoop实例, 如果在创建子进程前IOLoop实例被改变,会影响到每一个子进程。
- 所有进程一次性开启,没有办法不停实现不停服务更新
- 所有进程共享一个端口,单独监控每一个进程变得困难
以上原因,所以建议手动开启多个进程,绑定不同的端口。
(什么?你问怎么手动开启?传入不同的端口号,将脚本执行n次就开启了n个进程了,并且端口号不同。)
命令行参数设置
之前的程序都是将参数写死,能不能灵活设置呢?当然是可以的。
tornado.options模块,全局定义、存储参数。
- tornado.options.define()用来定义options选项变量的方法,定义的变量可以在全局的tornado.options.options中获取使用,传入参数:
- name 选项变量名,须保证全局唯一性,否则会报“Option ‘xxx’ already defined in …”的错误;
- default 选项变量的默认值,如不传默认为None;
- type 选项变量的类型,从命令行或配置文件导入参数的时候tornado会根据这个类型转换输入的值,转换不成功时会报错,可以是str、float、int、datetime、timedelta中的某个,若未设置则根据default的值自动推断,若default也未设置,那么不再进行转换。可以通过利用设置type类型字段来过滤不正确的输入。
- multiple 选项变量的值是否可以为多个,布尔类型,默认值为False,如果multiple为True,那么设置选项变量时值与值之间用英文逗号分隔,而选项变量则是一个list列表(若默认值和输入均未设置,则为空列表[])。
- help 选项变量的帮助提示信息,在命令行启动tornado时,通过加入命令行参数 —help 可以查看所有选项变量的信息(注意,代码中需要加入tornado.options.parse_command_line())。
- tornado.options.options
全局的options对象,所有定义的选项变量都会作为该对象的属性。 - tornado.options.parse_command_line()
转换命令行参数,并将转换后的值对应的设置到全局options对象相关属性上。
追加命令行参数的方式是server.py --option=value
修改程序:
import tornado.webimport tornado.ioloopimport tornado.httpserver# options模块import tornado.options- ``
# 定义服务器监听端口tornado.options.define("port", default=8000, type=int, help="run server on the given port")# 多值情况演示tornado.options.define("values", default=[], type=str, multiple=True, help="test values")- ``
- ``
class IndexHandler(tornado.web.RequestHandler):def get(self):self.write("Hello RedQueen!")- ``
- ``
if __name__ == "__main__":app = tornado.web.Application([(r"/", IndexHandler),])# 解析命令行参数tornado.options.parse_command_line()# 输出演示的多值情况print(tornado.options.options.values)http_server = tornado.httpserver.HTTPServer(app)# 监听定义的端口http_server.listen(tornado.options.options.port)# 提示信息print("请访问首页网址http://127.0.0.1:%s" % tornado.options.options.port)tornado.ioloop.IOLoop.current().start()
执行以下命令就能看到现象了:
python server.py --port=9000 --values=python,c++,java,php,ios
可以看到端口开在了9000端口上,而且console界面也输出了values的值
配置文件参数设置
命令行有的时候也不方便,那可以定义配置文吗?当然也是可以的。
我们在程序的同级目录下新建文件config
port = 8000values = ["python", "c++", "java", "php", "ios"]
你可能也发现了,配置文件的语法格式和Python的语法格式相同,事实上就是如此。
修改启动程序:
import tornado.webimport tornado.ioloopimport tornado.httpserver# options模块import tornado.options- ``
# 定义服务器监听端口tornado.options.define("port", default=8000, type=int, help="run server on the given port")# 多值情况演示tornado.options.define("values", default=[], type=str, multiple=True, help="test values")- ``
- ``
class IndexHandler(tornado.web.RequestHandler):def get(self):self.write("Hello RedQueen!")- ``
- ``
if __name__ == "__main__":app = tornado.web.Application([(r"/", IndexHandler),])# 从配置文解析参数tornado.options.parse_config_file("./config")# 输出演示的多值情况print(tornado.options.options.values)http_server = tornado.httpserver.HTTPServer(app)# 监听定义的端口http_server.listen(tornado.options.options.port)# 提示信息print("请访问首页网址http://127.0.0.1:%s" % tornado.options.options.port)tornado.ioloop.IOLoop.current().start()
然后直接执行server.py文件就可以了,可以看到执行的程序参数就是定义的配置文参数。
日志说明
当我们在代码中调用parse_command_line()或者parse_config_file()的方法时,tornado会默认配置标准logging模块,默认开启日志功能,并向标准输出(屏幕)打印日志信息。
如果想关闭tornado默认的日志功能,可以在命令行中添加—logging=none 或者在代码中执行如下操作:
from tornado.options import options, parse_command_lineoptions.logging = None-
配置文件导入配置
由于使用prase_config_file()的时候,还需要使用tornado.options.define()来进行定义,而且不能使用字典格式。所以使用配置文件的时候,建议新建一个python文件(如config.py),然后在里面直接定义python类型的变量(可以是任何的python类型);在需要配置文件参数的地方,将config.py作为模块导入,并使用其中的变量参数。
比如我们新建配置文件config.py #!/usr/bin/env pythonimport os- ``
# mariadb配置database = {'host': '127.0.0.1','port': 3306,'name': 'redqueen','user': 'redqueen','password': 'password',}- ``
# Tornado app配置settings = {'template_path': os.path.join(os.path.dirname(__file__), 'templates'),'static_path': os.path.join(os.path.dirname(__file__), 'statics'),'cookie_secret': '8z+&w@86wfck8g0p%@nj8ixr731n!n$mkter4sm3sja6n6bc&1','xsrf_cookies': False,'login_url': '/login','debug': True,}- ``
# 日志路径log_path = os.path.join(os.path.dirname(__file__), 'logs/all.log')
修改启动程序如下:
import tornado.webimport tornado.ioloopimport tornado.httpserverimport tornado.options- ``
# 导入配置文件import config- ``
# 定义服务器监听端口tornado.options.define("port", default=8000, type=int, help="run server on the given port")- ``
- ``
class IndexHandler(tornado.web.RequestHandler):def get(self):self.write("Hello RedQueen!")- ``
- ``
if __name__ == "__main__":# 将配置文件选项传入应用实例app = tornado.web.Application([(r"/", IndexHandler),], **config.settings)tornado.options.parse_command_line()http_server = tornado.httpserver.HTTPServer(app)http_server.listen(tornado.options.options.port)# 提示信息# python3.6 语法,注意版本,如果无法运行,更新方法就可以了print(f"请访问首页网址http://127.0.0.1:{tornado.options.options.port}")tornado.ioloop.IOLoop.current().start()
