Tornado 基于生成器的協(xié)程

2022-03-10 14:16 更新

tornado.gen 實現了基于生成器的協(xié)程。

注意:

本模塊中的“裝飾器和生成器”方法是 Python 3.5 中引入的原生協(xié)程(使用 ?async def? 和 ?await?)的先驅。 不需要與舊版本 Python 兼容的應用程序應該使用本機協(xié)程。 該模塊的某些部分仍然適用于原生協(xié)程,特別是 ?multi?、?sleep?、?WaitIterator和 ?with_timeout?。 其中一些函數在 ?asyncio模塊中有對應的函數,它們也可以使用,盡管這兩個函數不一定是 100% 兼容的。

與鏈接回調相比,協(xié)程提供了一種在異步環(huán)境中工作的更簡單的方法。 使用協(xié)程的代碼在技術上是異步的,但它被編寫為單個生成器,而不是單獨函數的集合。

例如,這是一個基于協(xié)程的處理程序:

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對象。

在 3.2 版更改:添加了字典支持。

在 4.1 版更改: 添加了對通過 ?singledispatch生成 ?asyncio Futures? 和 ?Twisted Deferreds? 的支持。

裝飾器

tornado.gen.coroutine(func: Union[Callable[[...], Generator[Any, Any, _T]], Callable[[...], _T]]) → Callable[[...], Future[_T]]

異步生成器的裝飾器。

為了與舊版本的 Python 兼容,協(xié)程也可以通過引發(fā)特殊異常 ?Return(value?) 來“?return?”。

帶有這個裝飾器的函數返回一個 ?Future?。

當協(xié)程內部發(fā)生異常時,異常信息將存儲在 ?Future對象中。 您必須檢查 ?Future對象的結果,否則您的代碼可能不會注意到異常。 這意味著如果從另一個協(xié)程調用時產生函數,使用 ?IOLoop.run_sync? 之類的東西進行頂級調用,或者將 ?Future傳遞給 ?IOLoop.add_future?。

在 6.0 版更改: ?callback?參數已刪除。 請改用返回的可等待對象。

exception tornado.gen.Return(value: Any = None)

從協(xié)程返回值的特殊異常。

如果引發(fā)此異常,則將其 ?value參數用作協(xié)程的結果:

@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參數是可選的,但從來沒有必要引發(fā) ?gen.Return()?。 ?return語句可以不帶參數使用。

實用功能

tornado.gen.with_timeout(timeout: Union[float, datetime.timedelta], future: Yieldable, quiet_exceptions: Union[Type[Exception], Tuple[Type[Exception], ...]] = ())

在?timeout?中包裝 ?Future?(或其他可產生的對象)。

如果輸入?future?在?timeout?之前未完成,則引發(fā) ?tornado.util.TimeoutError?,這可以以 ?IOLoop.add_timeout允許的任何形式指定(即 ?datetime.timedelta? 或相對于 ?IOLoop.time? 的絕對時間)

如果包裝的 ?Future在超時后失敗,則將記錄異常,除非它是 ?quiet_exceptions? 中包含的類型(可能是異常類型或類型序列)或 ?asyncio.CancelledError?。

當?timeout?到期時,包裝的 ?Future不會被取消,允許它被重用。 ?asyncio.wait_for? 與此函數類似,但它會在?timeout?時取消包裝的 ?Future?。

在 4.1 版更改: 添加了 ?quiet_exceptions 參數和未處理異常的日志記錄。

在 4.4 版更改: 添加了對 ?Future 以外的可縮性對象的支持。

在 6.0.3 版更改: ?asyncio.CancelledError? 現在總是被認為是“?quiet?”。

tornado.gen.sleep(duration: float) → Future[None]

返回在給定秒數后解析的 ?Future?。

當在協(xié)程中與 ?yield一起使用時,這是 ?time.sleep? 的非阻塞模擬(不應在協(xié)程中使用,因為它是阻塞的):

yield gen.sleep(0.5)

請注意,單獨調用此函數不會執(zhí)行任何操作; 你必須等待它返回的 ?Future(通常是通過?yielding it?)。

class tornado.gen.WaitIterator(*args, **kwargs)

提供一個迭代器以在等待對象完成時產生結果。

產生一組像這樣的等待對象:

results = yield [awaitable1, awaitable2]

暫停協(xié)程,直到 ?awaitable1和 ?awaitable2都返回,然后使用兩個 ?awaitables的結果重新啟動協(xié)程。 如果任一 ?awaitable引發(fā)異常,則表達式將引發(fā)該異常并且所有結果都將丟失。

如果你需要盡快得到每個 ?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實現了異步迭代器協(xié)議,因此它可以與 ?async for 語句一起使用(請注意,在此版本中,如果任何值引發(fā)異常,整個迭代都會中止,而前面的示例可以繼續(xù)過去個別錯誤):

async for result in gen.WaitIterator(future1, future2):
    print("Result {} received from {} at {}".format(
        result, wait_iterator.current_future,
        wait_iterator.current_index))

done() → bool

如果此迭代器沒有更多結果,則返回 ?True?。

next() → _asyncio.Future

返回將產生下一個可用結果的 ?Future?。

請注意,此 ?Future與任何輸入都不是同一個對象。

tornado.gen.multi(Union[List[Yieldable], Dict[Any, Yieldable]], quiet_exceptions: Union[Type[Exception], Tuple[Type[Exception], ...]] = ())

并行運行多個異步操作。

?children可以是一個列表,也可以是一個字典,其值是可產生的對象。?multi()? 返回一個新的 ?yieldable對象,該對象解析為包含其結果的并行結構。 如果 ?children是一個列表,則結果是一個相同順序的結果列表; 如果是字典,則結果是具有相同鍵的字典。

也就是說,?results = yield multi(list_of_futures)? 等價于:

results = []
for future in list_of_futures:
    results.append(yield future)

如果任何children?引發(fā)異常, ?multi()? 將引發(fā)第一個異常。 所有其他人都將被記錄,除非它們屬于 ?quiet_exceptions? 參數中包含的類型。

在基于 yield 的協(xié)程中,通常不需要直接調用此函數,因為協(xié)程運行程序會在產生列表或字典時自動執(zhí)行此操作。 但是,在基于 ?await的協(xié)程中是必需的,或者傳遞 ?quiet_exceptions 參數。

由于歷史原因,此函數在名稱 ?multi()? 和 ?Multi()? 下可用。

取消 ?multi()? 返回的 ?Future不會取消其子級。 ?asyncio.gather 類似于 ?multi()?,但它確實取消了它的?children?。

在 4.2 版更改: 如果多個 ?yieldable失敗,將記錄第一個之后的任何異常(引發(fā))。 添加了 ?quiet_exceptions參數以抑制所選異常類型的此日志記錄。

在 4.3 版更改: 用統(tǒng)一的函數 ?multi替換了類 ?Multi和函數 ?multi_future?。 添加了對 ?YieldPoint和 ?Future以外的支持。

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 版更改: 如果多個 ?Futures失敗,將記錄第一個(引發(fā))之后的任何異常。 添加了 ?quiet_exceptions參數以抑制所選異常類型的此日志記錄。

4.3 版后已棄用:改用 ?multi

tornado.gen.convert_yielded(yielded: Union[None, Awaitable[T_co], List[Awaitable[T_co]], Dict[Any, Awaitable[T_co]], concurrent.futures._base.Future]) → _asyncio.Future

將產生的對象轉換為 ?Future。

默認實現接受列表、字典和Futures。 這具有啟動任何沒有自己啟動的協(xié)程的副作用,類似于 ?asyncio.ensure_future?。

如果可以使用 ?singledispatch庫,則可以擴展此功能以支持其他類型。 例如:

@convert_yielded.register(asyncio.Future)
def _(asyncio_future):
    return tornado.platform.asyncio.to_tornado_future(asyncio_future)

tornado.gen.maybe_future(x: Any) → _asyncio.Future

將 x 轉換為 Future。

如果 x 已經是 Future,則簡單地返回它; 否則它會被包裹在一個新的 Future 中。 當您不知道 f() 是否返回 Future 時,這適合用作 result = yield gen.maybe_future(f()) 。

4.3 版后已棄用:此函數僅處理 ?Futures?,而不處理其他可生成對象。 不是 ?may_future?,而是檢查您期望的非?future?結果類型(通常只是 ?None?),并產生任何未知的結果。

tornado.gen.is_coroutine_function(func: Any) → bool

返回 func 是否為協(xié)程函數,即用?coroutine?包裹的函數。

tornado.gen.moment

一個特殊的對象,可以讓 ?IOLoop ?運行一次迭代。

這在正常使用中是不需要的,但它對長時間運行的協(xié)程很有幫助,這些協(xié)程可能會產生立即準備好的 Futures。

用法:?yield gen.moment?

在原生協(xié)程中,?yield gen.moment? 等同于 ?await asyncio.sleep(0)?。

4.0 版中的新功能。

4.5 版后已棄用:?yield None?(或沒有參數的 ?yield?)現在等同于 ?yield gen.moment?。


以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號