- истечет время ожидания;
- первая задача не вызовет исключение; или
- все задачи выполняются успешно
Код: Выделить всё
async def wait_and_reraise(futures: Sequence[asyncio.Task]) -> None:
try:
done, tasks_to_cancel = await asyncio.wait(
futures, timeout=5, return_when=asyncio.FIRST_EXCEPTION
)
except asyncio.CancelledError:
tasks_to_cancel = futures
raise
finally:
for task in tasks_to_cancel:
task.cancel()
for task in done:
if exc := task.exception():
raise exc
Из других ответов SO, сшитых вместе, следующее исправление (проверка длины выполненных задач, а также ожидание отмененных задач):
Код: Выделить всё
async def wait_and_reraise(tasks: Sequence[asyncio.Task]) -> None:
pending: None | Iterable[asyncio.Task] = None
try:
done, pending = await asyncio.wait(
tasks, timeout=5, return_when=asyncio.FIRST_EXCEPTION
)
except asyncio.CancelledError:
pending = tasks
raise
finally:
if pending:
for task in pending:
task.cancel()
await asyncio.gather(*pending, return_exceptions=True)
for task in done:
if exc := task.exception():
raise exc
if len(done) < len(tasks):
raise asyncio.TimeoutError("Tasks timed out before completion or exception.")
- Разумная ли это реализация? Не могу не задаться вопросом, есть ли еще какие-то проблемы, о которых я не рассказываю.
- Достаточно ли надежна логика отмены ожидающих задач? Зачем нужно ждать отмененных задач? Это значит, что ссылка на задачу не теряется и GC не добирается до нее до ее завершения (соответствующий пост)?