tornado.gen
— 基於產生器的協程¶
tornado.gen
實作基於產生器的協程。
注意
此模組中的「裝飾器與產生器」方法是原生協程(使用 async def
和 await
)的前身,後者已在 Python 3.5 中引入。不需要與舊版 Python 相容的應用程式應改用原生協程。此模組的某些部分仍適用於原生協程,特別是 multi
、 sleep
、 WaitIterator
和 with_timeout
。其中一些函式在 asyncio
模組中也有對應的函式,也可以使用,儘管兩者可能不一定 100% 相容。
協程提供比鏈式回呼更簡單的方式在非同步環境中工作。使用協程的程式碼在技術上是非同步的,但它被寫成單一產生器,而不是一系列獨立的函式。
例如,這是一個基於協程的處理常式
class GenAsyncHandler(RequestHandler):
@gen.coroutine
def get(self):
http_client = AsyncHTTPClient()
response = yield http_client.fetch("http://example.com")
do_something_with_response(response)
self.render("template.html")
Tornado 中的非同步函式會傳回 Awaitable
或 Future
;產生此物件會傳回其結果。
您也可以產生其他可產生物件的列表或字典,它們將同時啟動並並行執行;當它們全部完成時,將會傳回結果的列表或字典
@gen.coroutine
def get(self):
http_client = AsyncHTTPClient()
response1, response2 = yield [http_client.fetch(url1),
http_client.fetch(url2)]
response_dict = yield dict(response3=http_client.fetch(url3),
response4=http_client.fetch(url4))
response3 = response_dict['response3']
response4 = response_dict['response4']
如果匯入 tornado.platform.twisted
,也可以產生 Twisted 的 Deferred
物件。請參閱 convert_yielded
函式以擴充此機制。
在 3.2 版本變更: 新增字典支援。
在 4.1 版本變更: 透過 singledispatch
新增對產生 asyncio
Future 和 Twisted Deferred 的支援。
裝飾器¶
- tornado.gen.coroutine(func: Callable[[...], Generator[Any, Any, _T]]) Callable[[...], Future[_T]] [原始碼]¶
- tornado.gen.coroutine(func: Callable[[...], _T]) Callable[[...], Future[_T]]
用於非同步產生器的裝飾器。
為了與舊版 Python 相容,協程也可以透過引發特殊例外
Return(value)
來「傳回」。具有此裝飾器的函式會傳回
Future
。警告
當例外狀況在協程內部發生時,例外狀況資訊將會儲存在
Future
物件中。您必須檢查Future
物件的結果,否則您的程式碼可能會忽略例外狀況。這表示如果從另一個協程呼叫,則產生該函式,對於頂層呼叫使用類似IOLoop.run_sync
的方式,或將Future
傳遞至IOLoop.add_future
。在 6.0 版本變更: 已移除
callback
引數。請改用傳回的可等待物件。
- exception tornado.gen.Return(value: Optional[Any] = None)[原始碼]¶
從
coroutine
傳回值的特殊例外狀況。如果引發此例外狀況,則其 value 引數會用作協程的結果
@gen.coroutine def fetch_json(url): response = yield AsyncHTTPClient().fetch(url) raise gen.Return(json_decode(response.body))
在 Python 3.3 中,此例外狀況已不再必要:
return
陳述式可以直接用於傳回值(先前yield
和return
與值不能在同一個函式中組合)。類比 return 陳述式,value 引數是選擇性的,但永遠不需要
raise gen.Return()
。return
陳述式可以使用沒有引數的方式來取代。
實用函式¶
- tornado.gen.with_timeout(timeout: Union[float, datetime.timedelta], future: Yieldable, quiet_exceptions: Union[Type[Exception], Tuple[Type[Exception], ...]] = ())[原始碼]¶
將
Future
(或其他可 yield 的物件) 包裝在逾時設定中。如果輸入的 future 在
timeout
之前沒有完成,則會引發tornado.util.TimeoutError
。如果被包裝的
Future
在逾時後失敗,則會記錄異常,除非該異常的類型包含在quiet_exceptions
中 (可以是異常類型或類型序列),或是asyncio.CancelledError
。當逾時到期時,被包裝的
Future
不會被取消,允許它重複使用。asyncio.wait_for
與此函數類似,但它會在逾時時取消被包裝的Future
。4.0 版新增。
變更於 4.1 版: 新增
quiet_exceptions
引數以及記錄未處理的異常。變更於 4.4 版: 新增對
Future
以外的可 yield 物件的支援。變更於 6.0.3 版:
asyncio.CancelledError
現在總是視為 "quiet"。變更於 6.2 版:
tornado.util.TimeoutError
現在是asyncio.TimeoutError
的別名。
- tornado.gen.sleep(duration: float) Future[None] [原始碼]¶
傳回一個
Future
,該 Future 將在指定的秒數後解析。在協程中與
yield
一起使用時,這是time.sleep
的非阻塞類比 (不應在協程中使用,因為它是阻塞的)yield gen.sleep(0.5)
請注意,單獨呼叫此函式不會執行任何操作;您必須等待它傳回的
Future
(通常是 yield 它)。4.1 版新增。
- class tornado.gen.WaitIterator(*args: Future, **kwargs: Future)[原始碼]¶
提供一個迭代器,在 awaitable 完成時 yield 其結果。
像這樣 yield 一組 awaitable
results = yield [awaitable1, awaitable2]
會暫停協程,直到
awaitable1
和awaitable2
都傳回,然後用兩個 awaitable 的結果重新啟動協程。如果任一 awaitable 引發異常,則此運算式將會引發該異常,並且所有結果都將遺失。如果您需要盡快取得每個 awaitable 的結果,或者即使其他 awaitable 產生錯誤,您仍然需要某些 awaitable 的結果,則可以使用
WaitIterator
wait_iterator = gen.WaitIterator(awaitable1, awaitable2) while not wait_iterator.done(): try: result = yield wait_iterator.next() except Exception as e: print("Error {} from {}".format(e, wait_iterator.current_future)) else: print("Result {} received from {} at {}".format( result, wait_iterator.current_future, wait_iterator.current_index))
由於結果會在其可用時立即傳回,因此迭代器的輸出順序將與輸入引數的順序不同。如果您需要知道哪個 future 產生目前結果,則可以使用屬性
WaitIterator.current_future
或WaitIterator.current_index
來取得輸入清單中 awaitable 的索引。(如果WaitIterator
的建構中使用關鍵字引數,則current_index
將使用對應的關鍵字)。在 Python 3.5 中,
WaitIterator
實作了非同步迭代器協定,因此它可以與async for
陳述式一起使用 (請注意,在此版本中,如果任何值引發異常,則整個迭代將中止,而先前的範例可以繼續處理個別錯誤)async for result in gen.WaitIterator(future1, future2): print("Result {} received from {} at {}".format( result, wait_iterator.current_future, wait_iterator.current_index))
4.1 版新增。
變更於 4.3 版: 在 Python 3.5 中新增
async for
支援。
- tornado.gen.multi(Union[List[Yieldable], Dict[Any, Yieldable]], quiet_exceptions: Union[Type[Exception], Tuple[Type[Exception], ...]] = ())[原始碼]¶
並行執行多個非同步操作。
children
可以是清單或字典,其值是可 yield 的物件。multi()
會傳回一個新的可 yield 物件,該物件解析為包含其結果的並行結構。如果children
是清單,則結果是依相同順序排列的結果清單;如果是字典,則結果是具有相同索引鍵的字典。也就是說,
results = yield multi(list_of_futures)
等效於results = [] for future in list_of_futures: results.append(yield future)
如果任何子項目引發例外,
multi()
將會引發第一個例外。除非例外類型包含在quiet_exceptions
參數中,否則其他例外都會被記錄下來。在基於
yield
的協程中,通常不需要直接呼叫此函式,因為協程執行器會在 yield 列表或字典時自動執行。然而,在基於await
的協程中,或需要傳遞quiet_exceptions
參數時,則需要呼叫此函式。由於歷史原因,此函式可使用
multi()
和Multi()
這兩個名稱。取消
multi()
返回的Future
不會取消其子項目。asyncio.gather
與multi()
相似,但它會取消其子項目。變更於 4.2 版: 如果多個 yieldable 物件失敗,第一個 (會被引發) 之後的任何例外都會被記錄下來。新增了
quiet_exceptions
參數,以抑制針對選定例外類型的記錄。變更於 4.3 版: 將類別
Multi
和函式multi_future
替換為統一的函式multi
。新增了對YieldPoint
和Future
以外的 yieldable 物件的支援。
- tornado.gen.multi_future(Union[List[Yieldable], Dict[Any, Yieldable]], quiet_exceptions: Union[Type[Exception], Tuple[Type[Exception], ...]] = ())[原始碼]¶
平行等待多個非同步 future。
自 Tornado 6.0 起,此函式與
multi
完全相同。4.0 版新增。
變更於 4.2 版: 如果多個
Future
失敗,第一個 (會被引發) 之後的任何例外都會被記錄下來。新增了quiet_exceptions
參數,以抑制針對選定例外類型的記錄。自 4.3 版起已棄用: 請改用
multi
。
- tornado.gen.convert_yielded(yielded: Union[None, Awaitable, List[Awaitable], Dict[Any, Awaitable], Future]) Future [原始碼]¶
將 yield 的物件轉換為
Future
。預設實作接受列表、字典和 Future。這會產生啟動任何未自行啟動的協程的副作用,類似於
asyncio.ensure_future
。如果
singledispatch
函式庫可用,則可以擴展此函式以支援其他類型。例如:@convert_yielded.register(asyncio.Future) def _(asyncio_future): return tornado.platform.asyncio.to_tornado_future(asyncio_future)
4.1 版新增。
- tornado.gen.maybe_future(x: Any) Future [原始碼]¶
將
x
轉換為Future
。如果
x
已經是Future
,則直接傳回;否則會將其包裝在新的Future
中。當您不知道f()
是否傳回Future
時,適用於作為result = yield gen.maybe_future(f())
使用。自 4.3 版起已棄用: 此函式僅處理
Future
,而不處理其他 yieldable 物件。請檢查您預期的非 Future 結果類型 (通常僅為None
),然後yield
任何未知的結果,而不要使用maybe_future
。
- tornado.gen.is_coroutine_function(func: Any) bool [原始碼]¶
返回 func 是否為協程函式,即用
coroutine
包裝的函式。4.5 版新增功能。
- tornado.gen.moment¶
一個可以 yield 的特殊物件,允許 IOLoop 運行一個迭代。
這在正常使用中不需要,但在可能立即 yield 準備就緒的 Future 的長時間運行的協程中可能會有幫助。
用法:
yield gen.moment
在原生協程中,與
yield gen.moment
等效的是await asyncio.sleep(0)
。4.0 版新增。
自 4.5 版起已棄用:
yield None
(或沒有引數的yield
) 現在等效於yield gen.moment
。