簡體   English   中英

從帶有異常的異步任務列表中收集結果

[英]Gathering results from an asyncio task list with exceptions

編碼...

import asyncio
import random
from time import perf_counter
from typing import Iterable
from pprint import pprint

async def coro(n, i, threshold=0.4):
    await asyncio.sleep(i)
    if i > threshold:
        # For illustration's sake - some coroutines may raise,
        # and we want to accomodate that and just test for exception
        # instances in the results of asyncio.gather(return_exceptions=True)
        raise Exception(f"{i} of Task-{n} is too high")
    return i

async def main(it: Iterable, timeout: float) -> tuple:
    tasks = [asyncio.create_task(coro(i+1, d), name=f"Task-{i+1}") for i, d in enumerate(it)]
    await asyncio.wait(tasks, timeout=timeout)
    return tasks  # *not* (done, pending)

timeout = 0.5
random.seed(444)
n = 10
it = [random.random() for _ in range(n)]
start = perf_counter()
tasks = asyncio.run(main(it=it, timeout=timeout))
elapsed = perf_counter() - start
print(f"Done main({n}) in {elapsed:0.2f} seconds\n")
pprint(tasks)
print('----')

# does not work from here on....

res = []
for t in tasks:
    try:
        r = t.result() # gives an error!!!
    except Exception as e:
        res.append(e)
    else:
        res.append(r)
pprint(res)

...不適用於收集任務結果。 它失敗了...

Traceback (most recent call last):
  File "c:\Users\user\Documents\user\projects\learn\asyncio\wrap_gather_in_timeout.py", line 8, in coro
    await asyncio.sleep(i)
  File "C:\Users\user\AppData\Local\Programs\Python\Python39\lib\asyncio\tasks.py", line 654, in sleep
    return await future
asyncio.exceptions.CancelledError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "c:\Users\user\Documents\user\projects\learn\asyncio\wrap_gather_in_timeout.py", line 35, in <module>
    r = t.result()
asyncio.exceptions.CancelledError
Task exception was never retrieved
future: <Task finished name='Task-7' coro=<coro() done, defined at c:\Users\user\Documents\user\projects\learn\asyncio\wrap_gather_in_timeout.py:7> exception=Exception('i too high')>
Traceback (most recent call last):
  File "c:\Users\user\Documents\user\projects\learn\asyncio\wrap_gather_in_timeout.py", line 13, in coro
    raise Exception("i too high")
Exception: i too high

該代碼在 python 3.9 中運行。 知道我哪里出錯了,為什么?

是不是因為任務拋出異常后需要取消? 我無法成功實施它。

靈感來源:包裝 asyncio.gather SO 的解決方案

您的代碼有效,您無法成功創建res的問題是因為代碼不會引發正常的Exception class。 由於任務失敗,它最終會調用asyncio.exceptions.CancelledError ,如果我們查看文檔,它繼承自BaseException而不是Exception 自 Python 3.8 起,此更改是新的,並且由於您使用的是 Python 3.9,因此該更改已生效。 將您的代碼稍微更改為以下結果:

res = []
for t in tasks:
    try:
        r = t.result() # gives an error!!!
    except BaseException as e:
        res.append(e)
        continue
    res.append(r)

print(res)
[0.3088946587429545,
 0.01323751590501987,
 Exception('0.4844375347808497 of Task-3 is too high'),
 asyncio.exceptions.CancelledError(),
 asyncio.exceptions.CancelledError(),
 asyncio.exceptions.CancelledError(),
 Exception('0.4419557492849159 of Task-7 is too high'),
 0.3113884366691503,
 0.07422124156714727,
 asyncio.exceptions.CancelledError()]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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