一 、Torando
的介绍
Tornado
是一个Python web
框架和异步网络库, 通过使用非阻塞网络I/O
, Tornado
可以支撑上万级的连接,处理 长连接,WebSockets
,和其他需要与每个用户保持长久连接的应用.
说明:
Tornado 应该运行在类 Unix 的平台上, 在线上部署的时候,为了最佳的性能和扩展性,仅推荐 Linux 和 BSD平台,因为需要充分利用
linux
的epoll
和BSD的Kqueue
,这个也是Tornado不依靠多进程/多线程也能达到高性能的原因。
https://www.cnblogs.com/jeakeven/p/5435916.html
select epoll参考这里
二、Torando
和Django
的比较
特性 | Django |
Torando |
---|---|---|
路由系统 | 有 | 有 |
视图函数 | 有 | 有 |
模板引擎 | 有 | 有 |
ORM 操作 |
有 | 无 |
cookie | 有 | 有 |
session | 有 | 无 |
缓存,信号,Form,Admin |
有 | 无 |
Torando
入门程序
'''
tornado 的基础 web 框架模块
'''
import tornado.web
#tornado用来定义变量,导入配置文件的有 define() 、options、 parse_command_line()、parse_config_file(path) 一般我们不用
import tornado.options
'''
tornado 的核心 IO 循环模块,封装了 linux 的 epoll 和 BSD 的 Kqueue, 是 Tornado 高效的基础
'''
import tornado.ioloop
#视图类
class IndexHandler(tornado.web.RequestHandler):
# 处理 get 请求的
def get(self):
# 将数据返回给 web 的页面,类似于 HttpResponse
self.write('this is web page!')
# 处理post 请求的
def post(self, *args, **kwargs):
print(*args, **kwargs)
class StoryHandler(tornado.web.RequestHandler):
def get(self, id, *args, **kwargs):
print(id, args, kwargs)
self.write(id)
if __name__ == '__main__':
'''
实例化一个对象
Application 是 tornado.web 的一个核心类
里面保存了路由映射表,有一个 listen 方法, 创建了一个 socket 服务器,并绑定了一个端口 8001
'''
app = tornado.web.Application([
(r'/', IndexHandler),
(r'/story/([a-zA-Z0-9]+)/', StoryHandler)
])
# 绑定监听端口, 此时我们的服务器并没有开始监听
app.listen(8001)
'''
IOLoop.current:返回当前线程的 IOLoop 实例
IOLoop.start: 启动 IOLoop 实例的 I/O 循环,同时开启了监听
'''
tornado.ioloop.IOLoop.current().start()
执行过程:
- 第一步:执行脚本,监听
8888
端口 - 第二步:浏览器客户端访问
http://127.0.0.1:8888/
- 第三步:服务器接受请求,并交由对应的类处理该请求
- 第四步:类接受到请求之后,根据请求方式(
post/get/delete...
)的不同调用并执行相应的方法 - 第五步:方法返回值的字符串内容发送浏览器
HttpServer
的介绍
import tornado.httpserver
# 实例化一个httpserver的实例
httpServer = tornado.httpserver.HTTPServer(app)
# 绑定端口
httpServer.listen(8000)
但上述 tornado 默认启动的是一个进程
如何启动多个进程?
import tornado.httpserver
# 实例化一个httpserver的实例
httpServer = tornado.httpserver.HTTPServer(app)
# 绑定端口
<!-- httpServer.listen(8000) -->
httpServer.bind(8000) # 将服务器绑定到指定到端口
httpServer.start(5) # num默认开启一个进程, 如果值大于0,创建对应个数的进程
但是上面存在三个问题:
- 所有的子进程都是由一个命令启动的,无法做到不停止服务的情况下修改代码。如果我想修改某一个进程中的代码,就必须得停止所有的
- 所有的进程都共享一个端口号,想要分别监控非常困难
由于上面的问题, 我们不建议使用上面的方式开启多个进程, 因此我们以后建议使用 app.listen(8000)
options的使用
tornado为我们提供了一个便捷的 tornado.options
模块
基础方法与属性:
tornado.options.define()
: 用来定义变量的方法
参数:
name : 变量名, 必须保证其唯一性, 不然会报错
default: 默认值
type : 设置变量的类型, 传入值的时候, 会根据类型进行转换, 转换失败回报错, 可以是 str, int , float, 如果没有设置,则会根据default的值进行转换, 但如果default没有设置, 那么则不会进行转换
help : 提示信息
### 使用示例:
tornado.options.define('port', default = 8000)
tornado.options.define('list', default = [], type=str, mutiple=True)
tornado.options.options
: 全局的 options 对象, 所有定义的变量, 都可以作为该对象的属性
tornado.options.options.port
tornado.options.parse_command_line()
: 转换命令行参数, 并将转换的参数值保存在 options对象中
python server.py --port=9000 --list=good,stephen,lxx
tornado.options.parse_config_file(path)
: 从配置文件导入参数
加载在同一级的config文件,config是文本文件
tornado.options.parse_config_file("config")
缺点:
- 上述的配置文件方式要求我们必须使用 Python 的语法格式去写
- 调用参数的时候,不支持字典类型
因此使用下面的方式:
创建一个 config.py
的文件
#config.py 文件
options = {
"port" : 8080,
"names" : ["stephen", 'lxxx', 'xxx']
}
#其他使用
import config
print("list:", config.options.port
三、Torando
快速开始
基础工程推荐结构
├── application.py : 管理路由映射关系文件
├── config.py : 所有的配置文件
├── models : 数据库文件夹
├── server.py : 启动服务文件
├── static : 项目静态目录文件
├── template : 项目模板文件
└── views : 项目的视图处理文件夹
├── __init__.py
└── index.py
各个文件的代码:
application.py
文件:
#author:shangzekai
import tornado.web
from views import index
import config
class Application(tornado.web.Application):
def __init__(self):
path = [
(r'/', index.IndexHandler),
]
super(Application, self).__init__(path, **config.settings)
server.py
文件:
import config
import tornado.ioloop
from application import Application
if __name__ == '__main__':
app = Application()
app.listen(config.options['port'])
'''
IOLoop.current:返回当前线程的 IOLoop 实例
IOLoop.start: 启动 IOLoop 实例的 I/O 循环,同时开启了监听
'''
tornado.ioloop.IOLoop.current().start()
#tornado.ioloop.IOloop.instance().start() 跟上面是一样的,官方推荐使用current()
config.py
文件:
import os
BASE_DIR = os.path.dirname(__file__)
options = {
'port':8888
}
mysql = {
'dbhost':'127.92.8.134',
'dbuser':'root',
'dbpwd':'123456',
'dbname':'test',
'dbcharset':'utf8'
}
settings = {
'debug' : True,
'static_path' : os.path.join(BASE_DIR, 'static')