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
? 的支持。
異步生成器的裝飾器。
為了與舊版本的 Python 兼容,協(xié)程也可以通過引發(fā)特殊異常 ?Return(value
?) 來“?return
?”。
帶有這個裝飾器的函數返回一個 ?Future
?。
當協(xié)程內部發(fā)生異常時,異常信息將存儲在 ?Future
對象中。 您必須檢查 ?Future
對象的結果,否則您的代碼可能不會注意到異常。 這意味著如果從另一個協(xié)程調用時產生函數,使用 ?IOLoop.run_sync
? 之類的東西進行頂級調用,或者將 ?Future
傳遞給 ?IOLoop.add_future
?。
在 6.0 版更改: ?callback
?參數已刪除。 請改用返回的可等待對象。
從協(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
語句可以不帶參數使用。
在?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
?”。
返回在給定秒數后解析的 ?Future
?。
當在協(xié)程中與 ?yield
一起使用時,這是 ?time.sleep
? 的非阻塞模擬(不應在協(xié)程中使用,因為它是阻塞的):
yield gen.sleep(0.5)
請注意,單獨調用此函數不會執(zhí)行任何操作; 你必須等待它返回的 ?Future
(通常是通過?yielding it
?)。
提供一個迭代器以在等待對象完成時產生結果。
產生一組像這樣的等待對象:
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))
如果此迭代器沒有更多結果,則返回 ?True
?。
返回將產生下一個可用結果的 ?Future
?。
請注意,此 ?Future
與任何輸入都不是同一個對象。
并行運行多個異步操作。
?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
以外的支持。
并行等待多個異步?future
?。
從 Tornado 6.0 開始,這個功能和 ?multi
完全一樣。
4.0 版中的新功能。
在 4.2 版更改: 如果多個 ?Futures
失敗,將記錄第一個(引發(fā))之后的任何異常。 添加了 ?quiet_exceptions
參數以抑制所選異常類型的此日志記錄。
4.3 版后已棄用:改用 ?multi
。
將產生的對象轉換為 ?Future
。
默認實現接受列表、字典和Futures。 這具有啟動任何沒有自己啟動的協(xié)程的副作用,類似于 ?asyncio.ensure_future
?。
如果可以使用 ?singledispatch
庫,則可以擴展此功能以支持其他類型。 例如:
@convert_yielded.register(asyncio.Future)
def _(asyncio_future):
return tornado.platform.asyncio.to_tornado_future(asyncio_future)
將 x 轉換為 Future。
如果 x 已經是 Future,則簡單地返回它; 否則它會被包裹在一個新的 Future 中。 當您不知道 f() 是否返回 Future 時,這適合用作 result = yield gen.maybe_future(f()) 。
4.3 版后已棄用:此函數僅處理 ?Futures
?,而不處理其他可生成對象。 不是 ?may_future
?,而是檢查您期望的非?future
?結果類型(通常只是 ?None
?),并產生任何未知的結果。
返回 func 是否為協(xié)程函數,即用?coroutine
?包裹的函數。
一個特殊的對象,可以讓 ?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
?。
更多建議: