tornado.gen — 基於產生器的協程

tornado.gen 實作基於產生器的協程。

注意

此模組中的「裝飾器與產生器」方法是原生協程(使用 async defawait)的前身,後者已在 Python 3.5 中引入。不需要與舊版 Python 相容的應用程式應改用原生協程。此模組的某些部分仍適用於原生協程,特別是 multisleepWaitIteratorwith_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 中的非同步函式會傳回 AwaitableFuture;產生此物件會傳回其結果。

您也可以產生其他可產生物件的列表或字典,它們將同時啟動並並行執行;當它們全部完成時,將會傳回結果的列表或字典

@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 陳述式可以直接用於傳回值(先前 yieldreturn 與值不能在同一個函式中組合)。

類比 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]

會暫停協程,直到 awaitable1awaitable2 都傳回,然後用兩個 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_futureWaitIterator.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 支援。

done() bool[原始碼]

如果此迭代器沒有其他結果,則傳回 True。

next() Future[原始碼]

傳回一個 Future,該 Future 將 yield 下一個可用的結果。

請注意,此 Future 不會與任何輸入物件相同。

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.gathermulti() 相似,但它會取消其子項目。

變更於 4.2 版: 如果多個 yieldable 物件失敗,第一個 (會被引發) 之後的任何例外都會被記錄下來。新增了 quiet_exceptions 參數,以抑制針對選定例外類型的記錄。

變更於 4.3 版: 將類別 Multi 和函式 multi_future 替換為統一的函式 multi。新增了對 YieldPointFuture 以外的 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