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

2022-03-10 14:16 更新

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

注意:

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

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

例如,這是一個(gè)基于協(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 中的異步函數(shù)返回一個(gè) ?Awaitable或 ?Future?; 產(chǎn)生這個(gè)對(duì)象會(huì)返回它的結(jié)果。

您還可以產(chǎn)出其他可縮性對(duì)象的列表或字典,它們將同時(shí)啟動(dòng)并并行運(yùn)行; 全部完成后將返回結(jié)果列表或字典:

@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']

如果導(dǎo)入了 ?tornado.platform.twisted?,也可以生成 ?Twisted的 ?Deferred對(duì)象。

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

在 4.1 版更改: 添加了對(duì)通過 ?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?”。

帶有這個(gè)裝飾器的函數(shù)返回一個(gè) ?Future?。

當(dāng)協(xié)程內(nèi)部發(fā)生異常時(shí),異常信息將存儲(chǔ)在 ?Future對(duì)象中。 您必須檢查 ?Future對(duì)象的結(jié)果,否則您的代碼可能不會(huì)注意到異常。 這意味著如果從另一個(gè)協(xié)程調(diào)用時(shí)產(chǎn)生函數(shù),使用 ?IOLoop.run_sync? 之類的東西進(jìn)行頂級(jí)調(diào)用,或者將 ?Future傳遞給 ?IOLoop.add_future?。

在 6.0 版更改: ?callback?參數(shù)已刪除。 請(qǐng)改用返回的可等待對(duì)象。

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

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

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

@gen.coroutine
def fetch_json(url):
    response = yield AsyncHTTPClient().fetch(url)
    raise gen.Return(json_decode(response.body))

在 Python 3.3 中,不再需要這個(gè)異常:?return語句可以直接用于返回一個(gè)值(以前 ?yield和 ?return不能在同一個(gè)函數(shù)中組合使用)。

與 ?return語句類比, ?value參數(shù)是可選的,但從來沒有必要引發(fā) ?gen.Return()?。 ?return語句可以不帶參數(shù)使用。

實(shí)用功能

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

在?timeout?中包裝 ?Future?(或其他可產(chǎn)生的對(duì)象)。

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

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

當(dāng)?timeout?到期時(shí),包裝的 ?Future不會(huì)被取消,允許它被重用。 ?asyncio.wait_for? 與此函數(shù)類似,但它會(huì)在?timeout?時(shí)取消包裝的 ?Future?。

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

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

在 6.0.3 版更改: ?asyncio.CancelledError? 現(xiàn)在總是被認(rèn)為是“?quiet?”。

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

返回在給定秒數(shù)后解析的 ?Future?。

當(dāng)在協(xié)程中與 ?yield一起使用時(shí),這是 ?time.sleep? 的非阻塞模擬(不應(yīng)在協(xié)程中使用,因?yàn)樗亲枞模?/p>

yield gen.sleep(0.5)

請(qǐng)注意,單獨(dú)調(diào)用此函數(shù)不會(huì)執(zhí)行任何操作; 你必須等待它返回的 ?Future(通常是通過?yielding it?)。

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

提供一個(gè)迭代器以在等待對(duì)象完成時(shí)產(chǎn)生結(jié)果。

產(chǎn)生一組像這樣的等待對(duì)象:

results = yield [awaitable1, awaitable2]

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

如果你需要盡快得到每個(gè) ?awaitable的結(jié)果,或者如果你需要一些 ?awaitable的結(jié)果,即使是其他的產(chǎn)生錯(cuò)誤,你可以使用 ?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))

因?yàn)榻Y(jié)果一旦可用就會(huì)返回,迭代器的輸出與輸入?yún)?shù)的順序不同。 如果您需要知道哪個(gè) ?future產(chǎn)生了當(dāng)前結(jié)果,您可以使用屬性 ?WaitIterator.current_future? 或 ?WaitIterator.current_index? 從輸入列表中獲取 ?awaitable的索引。 (如果在 ?WaitIterator的構(gòu)造中使用了關(guān)鍵字參數(shù),?current_index將使用相應(yīng)的關(guān)鍵字)。

在 Python 3.5 上,?WaitIterator實(shí)現(xiàn)了異步迭代器協(xié)議,因此它可以與 ?async for 語句一起使用(請(qǐng)注意,在此版本中,如果任何值引發(fā)異常,整個(gè)迭代都會(huì)中止,而前面的示例可以繼續(xù)過去個(gè)別錯(cuò)誤):

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

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

next() → _asyncio.Future

返回將產(chǎn)生下一個(gè)可用結(jié)果的 ?Future?。

請(qǐng)注意,此 ?Future與任何輸入都不是同一個(gè)對(duì)象。

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

并行運(yùn)行多個(gè)異步操作。

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

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

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

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

在基于 yield 的協(xié)程中,通常不需要直接調(diào)用此函數(shù),因?yàn)閰f(xié)程運(yùn)行程序會(huì)在產(chǎn)生列表或字典時(shí)自動(dòng)執(zhí)行此操作。 但是,在基于 ?await的協(xié)程中是必需的,或者傳遞 ?quiet_exceptions 參數(shù)。

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

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

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

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

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

并行等待多個(gè)異步?future?。

從 Tornado 6.0 開始,這個(gè)功能和 ?multi完全一樣。

4.0 版中的新功能。

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

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

將產(chǎn)生的對(duì)象轉(zhuǎn)換為 ?Future。

默認(rèn)實(shí)現(xiàn)接受列表、字典和Futures。 這具有啟動(dòng)任何沒有自己?jiǎn)?dòng)的協(xié)程的副作用,類似于 ?asyncio.ensure_future?。

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

@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 轉(zhuǎn)換為 Future。

如果 x 已經(jīng)是 Future,則簡(jiǎn)單地返回它; 否則它會(huì)被包裹在一個(gè)新的 Future 中。 當(dāng)您不知道 f() 是否返回 Future 時(shí),這適合用作 result = yield gen.maybe_future(f()) 。

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

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

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

tornado.gen.moment

一個(gè)特殊的對(duì)象,可以讓 ?IOLoop ?運(yùn)行一次迭代。

這在正常使用中是不需要的,但它對(duì)長(zhǎng)時(shí)間運(yùn)行的協(xié)程很有幫助,這些協(xié)程可能會(huì)產(chǎn)生立即準(zhǔn)備好的 Futures。

用法:?yield gen.moment?

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

4.0 版中的新功能。

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


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)