asyncio中如何等待死循环内部创建的Task任务
问题根因
- 原代码中
main函数的while True是永久死循环,后续await asyncio.wait(tasks)以及异常处理逻辑永远不会执行,所有任务抛出的异常都没有被主动检索,进程退出时就会触发Task exception was never retrieved错误 - 额外小bug:
task = asyncio.create_task(parent_coro()),末尾多写了逗号,导致存入tasks列表的是单元素元组而非Task对象,就算后续逻辑能执行也会报错
修复代码
import asyncio async def parent_coro(): await child_coro() async def child_coro(): await asyncio.sleep(1) raise Exception('OMG!') async def main(): # 用集合存储任务,方便增删已完成的任务 tasks = set() while True: # 筛选出已完成的任务 finished_tasks = set() for task in tasks: if task.done(): finished_tasks.add(task) # 主动检索异常,避免未检索报错 try: exp = task.exception() if exp: print(f"捕获任务异常:{exp},即将重启任务") # 异常退出的任务自动重启 new_task = asyncio.create_task(parent_coro()) tasks.add(new_task) except Exception as e: print(f"任务处理失败:{e}") # 移除已完成的旧任务 tasks -= finished_tasks # 每秒新增1个任务,保留你原有的动态创建逻辑 new_task = asyncio.create_task(parent_coro()) tasks.add(new_task) await asyncio.sleep(1) if __name__ == '__main__': try: asyncio.run(main()) except KeyboardInterrupt: print("进程已手动终止")
逻辑说明
- 每次循环优先遍历所有存量任务,主动检查运行状态,对已完成的任务调用
exception()方法检索异常,从根源避免异常未检索的报错 - 检测到任务因异常终止时,自动创建新的同逻辑任务加入运行集合,满足你重启异常任务的需求
- 用集合存储任务相比列表更方便批量移除已完成的旧任务,避免内存无限增长
- 外层捕获
KeyboardInterrupt异常,按下Ctrl+C退出时不会打印冗余的中断堆栈
内容的提问来源于stack exchange,提问作者Antonio Romero Oca
相关产品推荐
相关产品推荐

