Tornado 4.3文檔翻譯: 用戶指南-異步和非阻塞I/O

譯者說

Tornado 4.3於2015年11月6日發佈,該版本正式支持Python3.5async/await關鍵字,而且用舊版本CPython編譯Tornado一樣可使用這兩個關鍵字,這無疑是一種進步。其次,這是最後一個支持Python2.6Python3.2的版本了,在後續的版本了會移除對它們的兼容。如今網絡上尚未Tornado4.3的中文文檔,因此爲了讓更多的朋友能接觸並學習到它,我開始了這個翻譯項目,但願感興趣的小夥伴能夠一塊兒參與翻譯,項目地址是tornado-zh on Github,翻譯好的文檔在Read the Docs上直接能夠看到。歡迎Issues or PR。git

異步和非阻塞I/O

實時web功能須要爲每一個用戶提供一個多數時間被閒置的長鏈接,在傳統的同步web服務器中,這意味着要爲每一個用戶提供一個線程,固然每一個線程的開銷都是很昂貴的.github

爲了儘可能減小併發鏈接形成的開銷,Tornado使用了一種單線程事件循環的方式.這就意味着全部的應用代碼都應該是異步非阻塞的,由於在同一時間只有一個操做是有效的.web

異步和非阻塞是很是相關的而且這兩個術語常常交換使用,但它們不是徹底相同的事情.服務器

阻塞

一個函數在等待某些事情的返回值的時候會被 阻塞. 函數被阻塞的緣由有不少:網絡I/O,磁盤I/O,互斥鎖等.事實上 每一個 函數在運行和使用CPU的時候都或多或少會被阻塞(舉個極端的例子來講明爲何對待CPU阻塞要和對待通常阻塞同樣的嚴肅: 好比密碼哈希函數bcrypt, 須要消耗幾百毫秒的CPU時間,這已經遠遠超過了通常的網絡或者磁盤請求時間了).網絡

一個函數能夠在某些方面阻塞在另一些方面不阻塞.例如, tornado.httpclient 在默認的配置下,會在DNS解析上面阻塞,可是在其餘網絡請求的時候不阻塞(爲了減輕這種影響,能夠用 ThreadedResolver 或者是經過正確配置 libcurltornado.curl_httpclient 來作).在Tornado的上下文中,咱們通常討論網絡I/O上下文的阻塞,儘管各類阻塞已經被最小化了.併發

異步

異步 函數在會在完成以前返回,在應用中觸發下一個動做以前一般會在後臺執行一些工做(和正常的 同步 函數在返回前就執行完全部的事情不一樣).這裏列舉了幾種風格的異步接口:curl

  • 回調參數異步

  • 返回一個佔位符 (.Future, Promise, Deferred)async

  • 傳送給一個隊列函數

  • 回調註冊表 (POSIX信號)

不論使用哪一種類型的接口, 按照定義 異步函數與它們的調用者都有着不一樣的交互方式;也沒有什麼對調用者透明的方式使得同步函數異步(相似 gevent使用輕量級線程的系統性能雖然堪比異步系統,但它們並無真正的讓事情異步).

例子

一個簡單的同步函數:

from tornado.httpclient import HTTPClient

    def synchronous_fetch(url):
        http_client = HTTPClient()
        response = http_client.fetch(url)
        return response.body

把上面的例子用回調參數重寫的異步函數:

from tornado.httpclient import AsyncHTTPClient

    def asynchronous_fetch(url, callback):
        http_client = AsyncHTTPClient()
        def handle_response(response):
            callback(response.body)
        http_client.fetch(url, callback=handle_response)

使用 Future 代替回調:

from tornado.concurrent import Future

    def async_fetch_future(url):
        http_client = AsyncHTTPClient()
        my_future = Future()
        fetch_future = http_client.fetch(url)
        fetch_future.add_done_callback(
            lambda f: my_future.set_result(f.result()))
        return my_future

Future 版本明顯更加複雜,可是 Futures 倒是Tornado中推薦的寫法.由於它有兩個主要的優點.首先是錯誤處理更加一致,由於 Future.result 方法能夠簡單的拋出異常(相較於常見的回調函數接口特別指定錯誤處理),並且 Futures 很適合和協程一塊兒使用.協程會在後面深刻討論.這裏是上面例子的協程版本,和最初的同步版本很像:

from tornado import gen

    @gen.coroutine
    def fetch_coroutine(url):
        http_client = AsyncHTTPClient()
        response = yield http_client.fetch(url)
        raise gen.Return(response.body)

raise gen.Return(response.body) 聲明是在Python 2 (and 3.2)下人爲執行的, 由於在其中生成器不容許返回值.爲了克服這個問題,Tornado的協程拋出一種特殊的叫 Return 的異常. 協程捕獲這個異常並把它做爲返回值.在Python 3.3和更高版本,使用 return response.body 有相同的結果.

相關文章
相關標籤/搜索