關於Python Web框架——Tornado

關於Tornado的入門看這篇文章,寫的很是好:html

https://zhuanlan.zhihu.com/p/37382503python

 

Tornado 是一個Python web框架和異步網絡庫,使用非阻塞網絡I/O。web

Tornado能夠被分爲4個主要的部分:redis

  • web框架
  • HTTP的客戶端和服務端實現
  • 異步網絡庫
  • 協程庫

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

Tornado:Hello, World

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服務器一般由四大組件組成。

  1. ioloop實例,它是全局的tornado事件循環,是服務器的引擎核心,示例中tornado.ioloop.IOLoop.current()就是默認的tornado ioloop實例。
  2. app實例,它表明着一個完成的後端app,它會掛接一個服務端套接字端口對外提供服務。一個ioloop實例裏面能夠有多個app實例,示例中只有1個,實際上能夠容許多個,不過通常幾乎不會使用多個。
  3. handler類,它表明着業務邏輯,咱們進行服務端開發時就是編寫一堆一堆的handler用來服務客戶端請求。
  4. 路由表,它將指定的url規則和handler掛接起來,造成一個路由映射表。當請求到來時,根據請求的訪問url查詢路由映射表來找到相應的業務handler。

這四大組件的關係是,一個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

https://zhuanlan.zhihu.com/p/37382503

https://www.tornadoweb.org/en/stable/ioloop.html

相關文章
相關標籤/搜索