Python中如何在终止事件循环前等待所有异步任务全部执行完成
标准实现方案
确保所有并发任务执行完成后再结束事件循环的核心原则是明确管理任务生命周期,不要依赖无差别捞取全局任务的方式,常见实现方案有两种:
方案1:显式持有并等待子任务引用(最佳实践)
不要丢弃asyncio.create_task()返回的任务对象,将其传递到上层等待完成,避免生命周期不可控。修改后代码如下:
import asyncio async def foo(delay): print("Start foo.") # Eg: Send message bar_task = asyncio.create_task(bar(delay)) print("End foo.") return bar_task # 向调用方返回后台任务引用 async def bar(delay): print("Start bar.") await asyncio.sleep(delay) print("End bar.") # Eg: Delete message after delay async def main(): bar_task = await foo(2) await bar_task # 显式等待后台任务执行完成 if __name__ == "__main__": asyncio.run(main())
该方案任务边界清晰,不会误等待无关任务,是生产环境的首选实现。
方案2:排除当前主任务后批量等待剩余任务
如果无法修改业务代码返回任务引用,可以修复你原来的全局等待逻辑,排除当前正在执行的主任务即可解决死锁问题:
import asyncio async def foo(delay): print("Start foo.") # Eg: Send message asyncio.create_task(bar(delay)) print("End foo.") async def bar(delay): print("Start bar.") await asyncio.sleep(delay) print("End bar.") # Eg: Delete message after delay async def main(): await foo(2) # 排除当前运行的main任务,避免自己等自己的死锁 current_task = asyncio.current_task() pending_tasks = [t for t in asyncio.all_tasks() if t is not current_task] if pending_tasks: await asyncio.wait(pending_tasks) if __name__ == "__main__": asyncio.run(main())
原问题原因说明
asyncio.run()的默认执行逻辑是:运行传入的协程直到返回后,会直接取消事件循环中所有剩余未完成的任务,再关闭事件循环。你最初的代码中bar任务没有被显式等待,foo返回后就会被直接取消,因此无法执行到End bar的输出。你之前修改后的代码死锁是因为main协程本身也属于asyncio.all_tasks()返回的列表之一,出现了自己等待自己的逻辑。
内容的提问来源于stack exchange,提问作者aiwl
相关产品推荐
相关产品推荐

