python - 从带有异常的异步任务列表中收集结果
问题描述
编码...
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 中运行。知道我哪里出错了,为什么?
是不是因为任务抛出异常后需要取消?我无法成功实施它。
解决方案
您的代码有效,您无法res
成功创建的问题是因为代码不只引发普通Exception
类。由于任务失败,它最终会调用asyncio.exceptions.CancelledError
which 如果我们查看文档继承自BaseException
not 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()]
推荐阅读
- python - /provider/'providers' 处的 Django NoReverseMatch 不是已注册的命名空间
- git - 将巨大的 SVN 存储库迁移到 GIT,并且 SVN 存储库上的冻结时间最短
- node.js - NodeJs - 接近堆限制分配失败 - JavaScript堆内存不足
- c# - 无法在 C# 中使用 RSA256 验证 json 有效负载中数据字段的签名
- c++ - 是否可以在“if”语句中声明变量?
- c++ - 如何在循环中随机化不同的值?C++
- c# - C# Automapper.Map 方法有什么区别?
- kotlin - Koin - 如何泛化 Singleton 创作?
- r - ggplot :绘制两条条和一条线?
- firebase - 在使用 Firebase 和 Flutter 进行身份验证时遇到问题