關於Tornado的入門看這篇文章,寫的很是好:html
https://zhuanlan.zhihu.com/p/37382503python
Tornado 是一個Python web框架和異步網絡庫,使用非阻塞網絡I/O。web
Tornado能夠被分爲4個主要的部分:redis
WSGI是Web Server Gateway Interface的縮寫。json
實時web功能須要爲每一個用戶提供一個多數時間被閒置的長鏈接, 在傳統的同步web服務器中,這意味着要爲每一個用戶提供一個線程, 固然每一個線程的開銷都是很昂貴的.後端
爲了儘可能減小併發鏈接形成的開銷,Tornado使用了一種單線程事件循環的方式. 這就意味着全部的應用代碼都應該是異步非阻塞的, 由於在同一時間只有一個操做是有效的.瀏覽器
知乎和掌閱的後端應該採用了這個框架。服務器
下面提供快速幫助回憶的代碼:(階乘服務和圓周率計算服務)網絡
# pi.py import json import math import redis import tornado.ioloop import tornado.web class FactorialService(object): def __init__(self, cache): self.cache = cache self.key = "factorials" def calc(self, n): s = self.cache.hget(self.key, str(n)) if s: return int(s), True s = 1 for i in range(1, n): s *= i self.cache.hset(self.key, str(n), str(s)) return s, False class PiService(object): def __init__(self, cache): self.cache = cache self.key = "pis" def calc(self, n): s = self.cache.hget(self.key, str(n)) if s: return float(s), True s = 0.0 for i in range(n): s += 1.0/(2*i+1)/(2*i+1) s = math.sqrt(s*8) self.cache.hset(self.key, str(n), str(s)) return s, False class FactorialHandler(tornado.web.RequestHandler): def initialize(self, factorial): self.factorial = factorial def get(self): n = int(self.get_argument("n") or 1) fact, cached = self.factorial.calc(n) result = { "n": n, "fact": fact, "cached": cached } self.set_header("Content-Type", "application/json; charset=UTF-8") self.write(json.dumps(result)) class PiHandler(tornado.web.RequestHandler): def initialize(self, pi): self.pi = pi def get(self): n = int(self.get_argument("n") or 1) pi, cached = self.pi.calc(n) result = { "n": n, "pi": pi, "cached": cached } self.set_header("Content-Type", "application/json; charset=UTF-8") self.write(json.dumps(result)) def make_app(): cache = redis.StrictRedis("localhost", 6379) factorial = FactorialService(cache) pi = PiService(cache) return tornado.web.Application([ (r"/fact", FactorialHandler, {"factorial": factorial}), (r"/pi", PiHandler, {"pi": pi}), ]) if __name__ == "__main__": app = make_app() app.listen(8888) tornado.ioloop.IOLoop.current().start()
由於兩個Handler都須要用到redis,因此咱們將redis單獨抽出來,經過參數傳遞進去。另外Handler能夠經過initialize函數傳遞參數,在註冊路由的時候提供一個字典就能夠傳遞任意參數了,字典的key要和參數名稱對應。咱們運行python pi.py
,打開瀏覽器訪問http://localhost:8888/pi?n=200
,能夠看到瀏覽器輸出{"cached": false, "pi": 3.1412743276, "n": 1000}
,這個值已經很是接近圓周率了。併發
下面來自知乎:(寫的很是好)
https://zhuanlan.zhihu.com/p/37382503
import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): self.write("Hello, world") def make_app(): return tornado.web.Application([ (r"/", MainHandler), ]) if __name__ == "__main__": app = make_app() app.listen(8888) tornado.ioloop.IOLoop.current().start()
這是官方提供了Hello, World實例,執行python hello.py
,打開瀏覽器訪問http://localhost:8888/就能夠看到服務器的正常輸出Hello, world
。
一個普通的tornado web服務器一般由四大組件組成。
tornado.ioloop.IOLoop.current()
就是默認的tornado ioloop實例。這四大組件的關係是,一個ioloop包含多個app(管理多個服務端口),一個app包含一個路由表,一個路由表包含多個handler。ioloop是服務的引擎核心,它是發動機,負責接收和響應客戶端請求,負責驅動業務handler的運行,負責服務器內部定時任務的執行。
當一個請求到來時,ioloop讀取這個請求解包成一個http請求對象,找到該套接字上對應app的路由表,經過請求對象的url查詢路由表中掛接的handler,而後執行handler。handler方法執行後通常會返回一個對象,ioloop負責將對象包裝成http響應對象序列化發送給客戶端。
同一個ioloop實例運行在一個單線程環境下。
關於ioloop:
tornado.ioloop — Main event loop
An I/O event loop for non-blocking sockets.(非阻塞套接字接口)
IOLoop is a wrapper around the asyncio event loop. (異步事件循環)
參考:
https://tornado-zh.readthedocs.io/zh/latest/guide/async.html