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
? 的支持。
異步生成器的裝飾器。
為了與舊版本的 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ì)象。
從協(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ù)使用。
在?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
?”。
返回在給定秒數(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
?)。
提供一個(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))
如果此迭代器沒有更多結(jié)果,則返回 ?True
?。
返回將產(chǎn)生下一個(gè)可用結(jié)果的 ?Future
?。
請(qǐng)注意,此 ?Future
與任何輸入都不是同一個(gè)對(duì)象。
并行運(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
以外的支持。
并行等待多個(gè)異步?future
?。
從 Tornado 6.0 開始,這個(gè)功能和 ?multi
完全一樣。
4.0 版中的新功能。
在 4.2 版更改: 如果多個(gè) ?Futures
失敗,將記錄第一個(gè)(引發(fā))之后的任何異常。 添加了 ?quiet_exceptions
參數(shù)以抑制所選異常類型的此日志記錄。
4.3 版后已棄用:改用 ?multi
。
將產(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)
將 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é)果。
返回 func 是否為協(xié)程函數(shù),即用?coroutine
?包裹的函數(shù)。
一個(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
?。
更多建議: