tornado的安裝
這里我使用的是虛擬環境中的pip安裝,配合清華大學鏡像源安裝的
pip install tornado -i https://pypi.tuna.tsinghua.edu.cn/simple
我的第一個tornado程序
import tornado.web
import tornado.ioloopclass IndexHandler(tornado.web.RequestHandler):'''主頁處理函數'''def get(self):self.write("hello tornado!")if __name__ == '__main__':app = tornado.web.Application([(r"/",IndexHandler)])app.listen(8000)tornado.ioloop.IOLoop.current().start()
在tornado中,直接執行就行,不用加任何參數也OK
因為在里面已經幫你創建了一個服務器了
初始tornado
什么是tornado
全稱tornado web server ,是一種web服務器軟件的開源版本
特點
作為web 框架,是一個輕量級的web框架,類似于另一個python web 框架 web.py,其擁有一部非阻塞IO的處理方式
作為 web 服務器,tornado 有較為出色的抗負載能力,官方用nginx反向dialing的方式部署tornado和其他python web 應用框架進行對比,結果最大瀏覽量超過第二名近40%
使用場景
- 用戶量大,高并發
- 大量的HTTP持久連接
- 使用同一個TCP連接來發送和接收多個HTTP請求/應答,而不是為每一個新的請求/應答打開新的連接方式
- 對于HTTP1.0,可以在請求的包頭(Header)中添加Connection: Keep-Alive。
- 對于HTTP 1.1,所有的連接默認都是持久連接。
C10K
上面的高并發的為題,通常用C10K這一概念來描述.C10K-Concurrently handling ten thousand connections ,即并發10000個連接,對于單臺服務器而言,根本無法承擔,而采用多臺服務器分布式又意味著高昂的成本
性能
tornado在設計之初就考慮到了性能因素,旨在解決C10K問題,這樣的設計使得其成為一個擁有非常高性能的解決方案(服務器與框架的集合體)
tornado和django對比
django
django是走大而全的方向,注重的是高效開發,它最出名的是其全自動化的管理后臺:只需要使用起ORM,做簡單的對象定義,它就能自動生成數據庫結構,以及全功能的管理后臺
Django提供的方便,也意味著Django內置的ORM跟框架內的其他模板耦合程度高,應用程序必須使用Django內置的ORM,否則就不能享受到框架內提供的種種基于其ORM的便利
特點:
- session功能
- 后臺管理
- ORM
tornado
tornado走的是少而精的方向,注重的是性能的優越,它最出名的是異步非阻塞的設計方式
特點
- HTTP服務器
- 異步編程
- webSockets
第一個程序的批注解釋1.0
import tornado.web
'''
tornado的基礎web框架模塊
'''
import tornado.ioloop
'''
tornado的核心IO循環模塊,
封裝了Linux的epoll和BSD的kqueue
這個是tornado高效的基礎
'''# 業務處理類
# 類比Django的視圖
class IndexHandler(tornado.web.RequestHandler):'''主頁處理函數'''# 處理GET請求的def get(self):'''這個get不是隨便寫的,是框架提前定義好的:return:'''# 對應HTTP請求的方法# 給瀏覽器響應信息self.write("hello tornado!")if __name__ == '__main__':# 這個路由和django差不多,只不過這個調用的是一個類# 實例化app應用對象# Application是tornado框架的核心,與服務器對接的接口# 里面保存了路由映射表,有一個listen方法,用來創建一個HTTP服務器的實例,并綁定了端口app = tornado.web.Application([(r"/",IndexHandler)])# 這個只是綁定在8000端口,注意:并沒有進行監聽奧app.listen(8000)# tornado的啟動方式# IOLoop.current():返回當前線程的IO實例# IOLoop.start(): 啟動實例的IO循環,同時開啟監聽tornado.ioloop.IOLoop.current().start()
第一個程序的批注解釋2.0
import tornado.web
'''
tornado的基礎web框架模塊
'''
import tornado.ioloop
'''
tornado的核心IO循環模塊,
封裝了Linux的epoll和BSD的kqueue
這個是tornado高效的基礎
'''# 引入httpserver模塊
import tornado.httpserver# 業務處理類
# 類比Django的視圖
class IndexHandler(tornado.web.RequestHandler):'''主頁處理函數'''# 處理GET請求的def get(self):'''這個get不是隨便寫的,是框架提前定義好的:return:'''# 對應HTTP請求的方法# 給瀏覽器響應信息self.write("main page info tornado!")if __name__ == '__main__':# 這個路由和django差不多,只不過這個調用的是一個類# 實例化app應用對象# Application是tornado框架的核心,與服務器對接的接口# 里面保存了路由映射表,有一個listen方法,用來創建一個HTTP服務器的實例,并綁定了端口app = tornado.web.Application([(r"/",IndexHandler)])# 這個只是綁定在8000端口,注意:并沒有進行監聽奧# app.listen(8000)# 實例化一個http服務器對象httpServer = tornado.httpserver.HTTPServer(app)# 綁定端口httpServer.listen(8000)# 這個和上面的listen可不一樣,兩個對象的方法,不同# 說白了,上面的一行,相當于我們這個兩行代碼的和# 這也就是tornado不用像Django那樣加上runserver參數啟動服務器了# 以為代碼中寫了tornado.ioloop.IOLoop.current().start()
第一個程序的批注解釋3.0
import tornado.web
import tornado.ioloop
import tornado.httpserverclass IndexHandler(tornado.web.RequestHandler):'''主頁處理函數'''def get(self):'''這個get不是隨便寫的,是框架提前定義好的:return:'''self.write("main page info tornado!")if __name__ == '__main__':app = tornado.web.Application([(r"/",IndexHandler)])httpServer = tornado.httpserver.HTTPServer(app)# httpServer.listen(8000)# 這里不用listen了,我們用bind# 將服務器綁定到指定的端口上httpServer.bind(8000)# 這里我寫幾個就開幾個進程'''默認開啟一個進程如果大于0,開啟多個進程值為none或者小于等于0的話,就開啟對應硬件機器CPU核心數的子進程'''httpServer.start(5)# 這個bind和start加一起就相當于 httpServer.listen(8000)了# 近期你可以多些一點,以為你要對于創建服務器的流程有一個了解,以后隨便寫# app.listen() 只能在單繼承模式中使用'''多進程: 雖然tornado給我們提供了一次性啟動多進程的方式,但是由于一些原因,我們不建議使用這種方式,來啟動多進程,而是手動啟動多進程,并且還能綁定多個端口多進程有三個問題:1. 每個紫禁城都會從父進程中復制出一份IOloop的實例,如果在創建紫禁城錢,修改了IOloop,會影響到所有的紫禁城實例2. 所有的進程都是由一個命令啟動的,無法做到在不停止服務的情況下修改代碼,這樣不好3. 所有進程共享一個端口,想要進行監控,有點難我自己來啟動的話,能在一個進程運行后,修改源代碼,來單獨在運行一遍,也OK'''tornado.ioloop.IOLoop.current().start()
第一個程序的批注解釋4.0
import tornado.web
import tornado.ioloop
import tornado.httpserver
import tornado.options"""
通常如果程序非正常結束
就會出現:"通常每個套接字地址(協議/網絡地址/端口)只允許使用一次"
這是因為端口沒有沒釋放
這時我們的debug模式還沒開啟tornado為我們提供了一tornado.option模塊
用于全局參數的定義/存儲/轉換
option:不讓端口寫死,讓option這個值從外部傳進來
基礎方法與屬性:
help : 其實就是選項變量的幫助提示信息,一般不用
"""# 這個函數的原型
'''
def define(name: str,default: Any = None,type: type = None,help: str = None,metavar: str = None,multiple: bool = False,group: str = None,callback: Callable[[Any], None] = None,
) -> None:
'''
# 這個函數的功能
'''
用來定義option選項變量的方法
'''
# 參數
'''
name : 選項變量名,必須保證其唯一性,否則會爆出一個option already define 錯誤
default : 設置選項變量的默認值,如果不傳,默認為none
type : 設置選項變量的類型,比如int,從命令行或者配置文件導入參數時,tornado會根據輸入的數據類型的值進行轉換會根據類型轉換成對應的值,轉換不成,會報錯,那么就有問題了可以:int float str datetime timedelta如果沒有設置type,會根據default的值進行轉換,如果default沒有設置,他就不進行轉換
multiple : 設置選項變量是否可以為多個值,默認為false
'''# 好我們可以先寫一個
tornado.options.define("port", default=8000, type=int)
# 我們要接受一個列表,列表里面的元素的字符串類型,默認給個空
tornado.options.define("list", default=[], type=str,multiple=True)# 然后我們還有一個屬性
'''
tornado.options.options
全局的options對象
所有定義的選項變量都會作為改對象的屬性
'''# 獲取參數的方法
'''
我們不是把這些參數賦值了么,我們還要把這些參數存儲起來
tornado.options.parse_command_line()作用:轉換命令行參數,將命令行參數抓換成為option的屬性
'''class IndexHandler(tornado.web.RequestHandler):def get(self):self.write("main page info tornado!")if __name__ == '__main__':# 轉換命令行參數,并保存在tornado.options.options里面tornado.options.parse_command_line()# 可以打印一下listprint('list->',tornado.options.options.list)app = tornado.web.Application([(r"/", IndexHandler)])httpServer = tornado.httpserver.HTTPServer(app)# 使用變量的值httpServer.bind(tornado.options.options.port)httpServer.start(1)tornado.ioloop.IOLoop.current().start()# 這樣我們在啟動的時候就能不需要修改代碼就能指定端口號了# 代碼能少改就少改變'''(venv) D:\PycharmProjects\itcast_tornado>python 01.py --port=9000 --list=good,nice,handsome,coollist-> ['good', 'nice', 'handsome', 'cool'][I 191205 17:13:54 web:2246] 200 GET / (127.0.0.1) 1.00ms[W 191205 17:13:54 web:2246] 404 GET /favicon.ico (127.0.0.1) 1.00ms'''
創建配置文件方式
在linux里面,所有的東西都是文件,就算他是目錄,都是文件
創建一個名為config的普通文件,位置在py文件的旁邊
內容如下:
port = 7000
list = ["good","nice","handsome"]
程序中這樣寫:
tornado.options.parse_config_file("config")
# 因為是同級目錄,所以相對路徑直接寫就OK了
然后正常運行程序就OK了
D:\PycharmProjects\itcast_tornado\venv\Scripts\python.exe D:/PycharmProjects/itcast_tornado/01.py
list-> ['good', 'nice', 'handsome']
[I 191205 17:27:21 web:2246] 200 GET / (127.0.0.1) 0.00ms
[W 191205 17:27:21 web:2246] 404 GET /favicon.ico (127.0.0.1) 0.00ms
我們現在有兩種方式來獲得參數,一種是命令行的一種是文件的,但是以后我們要使用哪種方式呢,???
都不是…
說明:
因為這個配置文件要按照python 的語法要求來進行書寫
調用參數的時候,不支持字典類型
最終版本:
創建一個名為config.py的文件
內容如下:
# 參數 字典類型的了options = {"port": 8080,"list": ["good", "nice", "handsome"]
}
腳本這樣寫:
import tornado.web
import tornado.ioloop
import tornado.httpserver
import tornado.options
import config# 獲取參數的方法
# 好我們可以先寫一個
tornado.options.define("port", default=8000, type=int)
# 我們要接受一個列表,列表里面的元素的字符串類型,默認給個空
tornado.options.define("list", default=[], type=str, multiple=True)class IndexHandler(tornado.web.RequestHandler):def get(self):self.write("main page info tornado!")if __name__ == '__main__':# 可以打印一下listprint('list->', config.options["list"])app = tornado.web.Application([(r"/", IndexHandler)])httpServer = tornado.httpserver.HTTPServer(app)# 使用變量的值httpServer.bind(config.options["port"])httpServer.start(1)tornado.ioloop.IOLoop.current().start()
這個config可以寫成模板,其中可以包含各種配置信息,不僅僅局限于這點兒
日志
當我們使用parse_command_line()或者parse_config_file(path)方法時
tornado會默認開啟logging模塊功能,向我們的屏幕打印一些相關信息
如果有處女座不想看這個信息,可以這樣
比如是從普通文件中導入的那種,要在后面再加上一句:
tornado.options.parse_config_file("config")
tornado.options.options.loggings = None