tornado異步web請求

1.爲何要使用異步web服務
使用異步非阻塞請求,併發處理更高效。html

2.同步與異步請求比較
同步請求時,web服務器進程是阻塞的,也就是說當一個請求被處理時,服務器進程會被掛起直至請求完成。python

異步請求時,web服務器進程在等待請求處理過程當中,讓I/O循環打開,以便服務於其餘請求,請求處理完成後繼續執行回調函數或生成器,而再也不是等待請求過程當中掛起進程。整個過程是異步的。web

3.同步與異步請求示例
同步請求:數據庫

class IndexHandler(tornado.web.RequestHandler):
    def get(self):
        client=tornado.httpclient.HTTPClient()
        response=client.fetch("http://test.com/list")
        self.write("success")

異步請求:數組

複製代碼

class IndexAsyncHandler(tornado.web.RequestHandler):
    @tornado.web.asynchronous
    def get(self):
        client=tornado.httpclient.AsyncHTTPClient()
        client.fetch("http://test.com/list",callback=self.on_response)
    def on_response(self,response):
        self.write("success")
        self.finish()

複製代碼

路由配置:緩存

(r'/test', test_async.IndexHandler),
(r'/testasync', test_async.IndexAsyncHandle)

使用http_load工具(關於http_load的使用參見「http_load使用詳解」)進行壓力測試,結果以下:
同步壓力測試:服務器

複製代碼

[root@51dev http_load-12mar2006]# ./http_load -p 100 -s 60 url
27 fetches, 100 max parallel, 189 bytes, in 60 seconds
7 mean bytes/connection
0.45 fetches/sec, 3.15 bytes/sec
msecs/connect: 0.113037 mean, 0.258 max, 0.021 min
msecs/first-response: 31186.5 mean, 59721.3 max, 2246.32 min
HTTP response codes:
code 200 -- 27

複製代碼

異步壓力測試:併發

複製代碼

209 fetches, 100 max parallel, 1463 bytes, in 60.0046 seconds
7 mean bytes/connection
3.48306 fetches/sec, 24.3814 bytes/sec
msecs/connect: 0.0944641 mean, 0.387 max, 0.021 min
msecs/first-response: 20088 mean, 30650 max, 10601.1 min
HTTP response codes:
code 200 -- 209

複製代碼

對比能夠看出,在60s時間內,併發請求數量爲100的狀況下,
同步請求只有27個請求響應,而異步請求達到了209個異步

4.異步請求使用說明
同步請求在請求完畢後,自動關閉鏈接。
異步請求保持鏈接開啓,須要手動關閉鏈接。
tornado中使用@tornado.web.asynchronous裝飾器做用是保持鏈接一直開啓,
回調函數執行完畢後,調用finish方法來主動關閉鏈接。async

5.異步生成器
上例中,是使用回調函數來作業務處理及關閉鏈接的。
回調函數的缺點是,可能引發回調深淵,系統將難以維護。如回調中調用回調。

複製代碼

def get(self):
    client = AsyncHTTPClient()
    client.fetch("http://example.com", callback=on_response)

def on_response(self, response):
    client = AsyncHTTPClient()
    client.fetch("http://another.example.com/", callback=on_response2)

def on_response2(self, response):
    client = AsyncHTTPClient()
    client.fetch("http://still.another.example.com/", callback=on_response3)

def on_response3(self, response):
    [etc., etc.]

複製代碼

tornado2.1引入了tornado.gen模塊,能夠更整潔地執行異步請求。
異步請求:

複製代碼

class IndexGenHandler(tornado.web.RequestHandler):
    @tornado.web.asynchronous
    @tornado.gen.engine
    def get(self):
        client=tornado.httpclient.AsyncHTTPClient()
        response=yield tornado.gen.Task(client.fetch,"http://test.com/list")
        self.write("success")
        self.finish()

複製代碼

路由配置:

(r'/testgen', test_async.IndexGenHandler),

異步壓力測試:

複製代碼

207 fetches, 100 max parallel, 1449 bytes, in 60.0055 seconds
7 mean bytes/connection
3.44968 fetches/sec, 24.1478 bytes/sec
msecs/connect: 0.113483 mean, 0.948 max, 0.024 min
msecs/first-response: 20156.5 mean, 32294.2 max, 9607.34 min
HTTP response codes:
code 200 -- 207

複製代碼

tornado.gen是一個生成器(關於生成器參見「python生成器,函數,數組」 ),
yield關鍵字的做用是返回控制,異步任務執行完畢後,程序在yield的地方恢復。
能夠看到使用生成器,異步後業務處理不是在回調函數中完成的,看起來像同步處理同樣,代碼邏輯更清晰。
使用生成器和回調函數異步請求是同樣的。

6.異步請求的適用場景 請求處理邏輯複雜耗時,或長時間請求數據庫的時候,異步請求能夠大幅提高併發請求效率。 同時綜合考慮緩存,業務邏輯放在客戶端等手段,來緩解服務器壓力。

相關文章
相關標籤/搜索