正在从包含异常的异步任务列表中收集结果



代码。。。

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} secondsn")
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:UsersuserDocumentsuserprojectslearnasynciowrap_gather_in_timeout.py", line 8, in coro
await asyncio.sleep(i)
File "C:UsersuserAppDataLocalProgramsPythonPython39libasynciotasks.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:UsersuserDocumentsuserprojectslearnasynciowrap_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:UsersuserDocumentsuserprojectslearnasynciowrap_gather_in_timeout.py:7> exception=Exception('i too high')>
Traceback (most recent call last):
File "c:UsersuserDocumentsuserprojectslearnasynciowrap_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类。由于任务失败,它最终调用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()]

最新更新