C10K—— Concurrently handling ten thousand connections,即并发10000个连接。对于单台服务器而言,根本无法承担,而采用多台服务器分布式又意味着高昂的成本
Tornado是2009年9月10日发布的一个用Python语言写成的Web服务器兼Web应用框架
Tornado在设计之初就考虑到了性能因素,旨在解决C10K
问题,这样的设计使得其成为一个拥有非常高性能
的框架
Django是走大而全的方向,注重的是高效开发,它最出名的是其全自动化的管理后台
Django提供的方便,也意味着Django内置的ORM跟框架内的其他模块耦合程度高
Tornado走的是少而精的方向,注重的是性能优越
最出名的是异步非阻塞的设计方式
关于Tornado的使用平台
Tornado应该运行在类Unix
平台,在线上部署时为了最佳的性能和扩展性,仅推荐Linux和BSD(因为充分利用Linux的epoll工具和BSD的kqueue工具,是Tornado不依靠多进程/多线程而达到高性能的原因)
对于Mac OS X,虽然也是衍生自BSD并且支持kqueue,但是其网络性能通常不太给力,因此仅推荐用于开发
import tornado.web
import tornado.ioloop
class HelloHandler(tornado.web.RequestHandler): # 封装一个请求对应的所有方法
def get(self):
self.write("hello world")
if __name__ == '__main__':
app = tornado.web.Application([
(r'/', HelloHandler), # 生成服务实例,通常包含路由信息
])
app.listen(8000) # 监听端口
tornado.ioloop.IOLoop.current().start() # 开启服务
RequestHandler
封装了对应一个请求的所有信息和方法
write(响应信息)就是写响应信息的一个方法,当没有对应请求方式的成员方法时,会返回“405: Method Not Allowed”错误
Application
Tornado Web框架的核心应用类,是与服务器对接的接口,里面保存了路由信息表
其listen(端口)方法用来创建一个http服务器实例,并绑定到给定端口(注意:此时服务器并未开启监听)
ioloop
tornado的核心io循环模块,封装了Linux的epoll和BSD的kqueue,tornado高性能的基石
tornado.httpserver模块就是tornado的HTTP服务器实现,而app.listen(8000)正是对这一过程的简写
import tornado.web
import tornado.ioloop
import tornado.httpserver
class HelloHandler(tornado.web.RequestHandler):
def get(self):
self.write("hello world")
if __name__ == '__main__':
app = tornado.web.Application([
(r'/', HelloHandler)
])
http_server = tornado.httpserver.HTTPServer(app) # 根据app对象生成http server实例对象
http_server.listen(8000) # 使用http server对象监听端口
tornado.ioloop.IOLoop.current().start()
http_server.bind(port)
将服务器绑定到指定端口
http_server.start(num_processes=1)
指定开启几个进程,参数num_processes默认值为1
num_processes为None或者<=0,则自动根据机器硬件的cpu核芯数创建同等数目的子进程
如果num_processes>0,则创建num_processes个子进程
# -*- coding: utf-8 -*-
# @Time : 2019/7/17 23:55
# @Author : Bryce Liu
# @FileName: tornado_1_3.py
import tornado.web
import tornado.ioloop
import tornado.httpserver
class HelloHandler(tornado.web.RequestHandler):
def get(self):
self.write("hello world")
if __name__ == '__main__':
app = tornado.web.Application([
(r'/', HelloHandler)
])
http_server = tornado.httpserver.HTTPServer(app)
http_server.bind(8000) # 服务绑定到8000端口
http_server.start(0) # 根据设备核数开启指定数量子进程
tornado.ioloop.IOLoop.current().start()
tornado.options模块是tornado提供的一个便捷的工具,用于全局参数定义、存储、转换
用来定义options选项变量的方法,定义的变量可以在全局的tornado.options.options中获取使用
“Option 'xxx' already defined in ...”
的错误;None
;str
、float
、int
、datetime
、timedelta
中的某个,若未设置则根据default的值自动推断,若default也未设置,那么不再进行转换False
list
列表(若默认值和输入均未设置,则为空列表[]
)--help
可以查看所有选项变量的信息(注意,代码中需要加入tornado.options.parse_command_line())。全局的options对象,所有定义的选项变量都会作为该对象的属性
转换命令行参数,并将转换后的值对应的设置到全局options对象相关属性上
追加命令行参数的方式是--myoption=myvalue
import tornado.web
import tornado.ioloop
import tornado.httpserver
import tornado.options
# 定义options涉及的参数
tornado.options.define("port", default=8000, type=int, help="define port")
tornado.options.define("language", default=[], type=str, multiple=True, help="just for test")
class HelloHandler(tornado.web.RequestHandler):
def get(self):
self.write("hello world")
if __name__ == '__main__':
# tornado.options.parse_command_line()获取命令中传递的参数,并保存到tornado.options.options的属性中
tornado.options.parse_command_line()
print(tornado.options.options.language) # 打印language
app = tornado.web.Application([
(r'/', HelloHandler)
])
http_server = tornado.httpserver.HTTPServer(app)
http_server.listen(tornado.options.options.port) # 获得传入的port
tornado.ioloop.IOLoop.current().start()
# 使用如下命令传入参数
# python tornado_1_4.py --port=9000 --language=python,c++,java
从配置文件导入option,配置文件中的选项格式如下
port = 9000
language = ["python","c++","java"]
当我们在代码中调用parse_command_line()
或者parse_config_file()
的方法时,tornado会默认为我们配置标准logging模块,即默认开启了日志功能
关闭默认日志:
可以在命令行中添加--logging=none
from tornado.options import options, parse_command_line
options.logging = None
parse_command_line()
还可以新建一个python配置文件(例如config.py),在配置文件中直接定义python类型的变量(通常使用字典类型)
在需要配置文件参数的地方,将config.py作为模块导入,并使用其中的变量参数
config.py
# conding:utf-8
import os
# 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': 'QJ76Hbd+N80XhKS7HCKskOUE2snIH06SHxXlG=',
'xsrf_cookies': False,
'login_url': '/login',
'debug': True,
}
# 日志
log_path = os.path.join(os.path.dirname(__file__), 'logs/log')
# conding:utf-8
import tornado.web
import config
...
if __name__ = "__main__":
app = tornado.web.Application([
(...)
], **config.settings)
...