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

jopen 8年前發布 | 16K 次閱讀 Tornado Python開發

譯者說

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。

異步和非阻塞I/O

實時web功能需要為每個用戶提供一個多數時間被閑置的長連接,在傳統的同步web服務器中,這意味著要為每個用戶提供一個線程,當然每個線程的開銷都是很昂貴的.

為了盡量減少并發連接造成的開銷,Tornado使用了一種單線程事件循環的方式.這就意味著所有的應用代碼都應該是異步非阻塞的,因為在同一時間只有一個操作是有效的.

異步和非阻塞是非常相關的并且這兩個術語經常交換使用,但它們不是完全相同的事情.

阻塞

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

一個函數可以在某些方面阻塞在另外一些方面不阻塞.例如, tornado.httpclient 在默認的配置下,會在DNS解析上面阻塞,但是在其他網絡請求的時候不阻塞(為了減輕這種影響,可以用 ThreadedResolver 或者是通過正確配置 libcurltornado.curl_httpclient 來做).在Tornado的上下文中,我們一般討論網絡I/O上下文的阻塞,盡管各種阻塞已經被最小化了.

異步

異步 函數在會在完成之前返回,在應用中觸發下一個動作之前通常會在后臺執行一些工作(和正常的 同步 函數在返回前就執行完所有的事情不同).這里列舉了幾種風格的異步接口:

  • 回調參數
  • 返回一個占位符 (.Future, Promise, Deferred)
  • 傳送給一個隊列
  • 回調注冊表 (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 有相同的結果.

來自: http://www.jianshu.com/p/bdef9d5df71b

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!