簡體   English   中英

asyncio.as_completed是否會產生期貨或協同程序?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM