[英]Does asyncio.as_completed yield Futures or coroutines?
來自asyncio
文檔 :
asyncio.as_completed(aws, *, loop=None, timeout=None)
同時在aws集中運行等待對象。 返回Future對象的迭代器。 返回的每個Future對象代表剩余等待項集合中最早的結果。
我假設每個這些的Future
對象具有在所描述的方法asyncio.Future
: .cancelled()
.exception()
和.result()
但似乎所產生的元素只是協程,而不是Future
對象。 我錯過了什么?
這似乎打敗了.as_completed()
的描述。 如果我需要await
它,協程如何“完成”?
>>> import asyncio
>>> import aiohttp
>>>
>>> async def get(session, url):
... async with session.request('GET', url) as resp:
... t = await resp.text()
... return t
...
>>> async def bulk_as_completed(urls):
... async with aiohttp.ClientSession() as session:
... aws = [get(session, url) for url in urls]
... for future in asyncio.as_completed(aws):
... for i in ('cancelled', 'exception', 'result'):
... print(hasattr(future, i))
... print(type(future))
... try:
... result = await future
... except:
... pass
... else:
... print(type(result))
... print()
...
>>>
>>> urls = (
... 'https://docs.python.org/3/library/asyncio-task.html',
... 'https://docs.python.org/3/library/select.html',
... 'https://docs.python.org/3/library/this-page-will-404.html',
... )
>>>
>>> asyncio.run(bulk_as_completed(urls))
False
False
False
<class 'coroutine'>
<class 'str'>
False
False
False
<class 'coroutine'>
<class 'str'>
False
False
False
<class 'coroutine'>
<class 'str'>
最終,我關心這個的原因是因為我想讓異常像asyncio.gather(..., return_exceptions=True)
那樣asyncio.gather(..., return_exceptions=True)
。 考慮在調用session.request()
時添加一個偽造的URL:
urls = (
'https://docs.python.org/3/library/asyncio-task.html',
'https://docs.python.org/3/library/select.html',
'https://docs.python.org/3/library/this-page-will-404.html',
# This URL will raise on session.request(). How can I propagate
# that exception to the iterator of results?
'https://asdfasdfasdf-does-not-exist-asdfasdfasdf.com'
)
我希望能夠做的就是這樣的事情(使用Future對象的方法,但這些都不是未來的目標可言,這是問題):
async def bulk_as_completed(urls):
async with aiohttp.ClientSession() as session:
aws = [get(session, url) for url in urls]
for future in asyncio.as_completed(aws):
if future.cancelled():
res = futures.CancelledError()
else:
exc = future.exception()
if exc is not None:
res = exc
else:
res = future.result()
# ...
# [Do something with `res`]
我希望能做的就像這樣[...]
也許不那么方便,但您應該能夠使用以下代碼提取異常:
async def bulk_as_completed(urls):
async with aiohttp.ClientSession() as session:
aws = [get(session, url) for url in urls]
for future in asyncio.as_completed(aws):
try:
res = await future
except Exception as e:
res = e
# ...
# [Do something with `res`]
這[產生協程而不是期貨]似乎打敗了
.as_completed()
的描述。 如果我需要等待它,協程如何“完成”?
不是。 首次實現asyncio.as_completed
時,異步迭代器不存在。 沒有異步迭代就沒有辦法在它們完成時返回期貨,所以as_completed
類型通過屈服(立即)虛擬等待來偽造它,人們必須等待獲得實際結果。
即使as_completed
產生了實際的期貨,也不會對你的用例有所幫助,因為如果沒有等待他們的人,這些期貨就無法完成。 為了提供as_completed
讓步完成的期貨的預期語義, as_completed
需要實現異步迭代,其等價的__next__
可以等待。
as_completed
的驚人行為之前已經提出,我已經通過提供異步迭代提交了一個問題來修復它。 一旦實現,您的原始代碼將只for
更改為async for
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.