新聞中心
異步和非阻塞 I/O
實時 Web 功能需要每個用戶的長期空閑連接。在傳統的同步 Web 服務器中,這意味著為每個用戶分配一個線程,這可能非常昂貴。

為了最小化并發(fā)連接的成本,Tornado 使用單線程事件循環(huán)。這意味著所有應用程序代碼都應該以異步和非阻塞為目標,因為一次只能激活一個操作。
術語異步和非阻塞密切相關,經?;Q使用,但它們并不完全相同。
阻塞
當一個函數在返回之前等待某事發(fā)生時會阻塞。一個函數可能會因為多種原因而阻塞:網絡 I/O、磁盤 I/O、互斥鎖等。事實上,每個函數在運行和使用 CPU 時都會阻塞,至少有一點點阻塞(舉一個極端的例子來演示為什么 CPU 阻塞必須像其他類型的阻塞一樣受到重視,請考慮密碼散列函數,如 bcrypt,其設計使用數百毫秒的 CPU 時間,遠遠超過典型的網絡或磁盤訪問)。
一個函數在某些方面可以是阻塞的,而在其他方面可以是非阻塞的。在 Tornado 的上下文中,我們通常在網絡 I/O 的上下文中討論阻塞,盡管所有類型的阻塞都將被最小化。
異步
異步函數在完成之前返回,并且通常會在觸發(fā)應用程序中的某些未來操作之前在后臺發(fā)生一些工作(與正常的 同步函數相反,它們在返回之前完成它們將要做的所有事情)。異步接口有多種風格:
- 回調參數
- 返回占位符 ( Future, Promise, Deferred)
- 交付到隊列
- 回調注冊表(例如 POSIX 信號)
無論使用哪種類型的接口, 根據定義,異步函數與其調用者的交互方式不同;沒有免費的方法可以以對其調用者透明的方式使同步函數異步(像gevent 之類的系統使用輕量級線程來提供與異步系統相當的性能,但它們實際上并沒有使事情異步)。
Tornado 中的異步操作通常返回占位符對象 ( Futures),但一些低級組件(例如IOLoop使用回調的組件)除外。Futures通常使用awaitoryield 關鍵字轉換成它們的結果。
演示例子
這是一個同步函數:
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
async def asynchronous_fetch(url):
http_client = AsyncHTTPClient()
response = await http_client.fetch(url)
return response.body或者為了與舊版本python兼容,請使用以下?tornado.gen?模塊
from tornado.httpclient import AsyncHTTPClient
from tornado import gen
@gen.coroutine
def async_fetch_gen(url):
http_client = AsyncHTTPClient()
response = yield http_client.fetch(url)
raise gen.Return(response.body)協程有點神奇,但它們在內部做的事情是這樣的:
from tornado.concurrent import Future
def async_fetch_manual(url):
http_client = AsyncHTTPClient()
my_future = Future()
fetch_future = http_client.fetch(url)
def on_fetch(f):
my_future.set_result(f.result().body)
fetch_future.add_done_callback(on_fetch)
return my_future請注意:協程?Future?在 fetch 完成之前返回它。這就是使協同程序異步的原因。
任何你可以用協程做的事情,你也可以通過傳遞回調對象來做,但是協程提供了一個重要的簡化,它讓你以與同步時相同的方式組織你的代碼。這對于錯誤處理尤其重要,因為?try?/?except?塊的工作方式與您在協程中所期望的一樣,而這很難通過回調實現。本指南的下一部分將深入討論協程
網站名稱:創(chuàng)新互聯Tornado教程:Tornado異步和非阻塞I/O
分享鏈接:http://www.5511xx.com/article/djdiigs.html


咨詢
建站咨詢
