如何在部分任务耗时过久时正确关闭asyncio gather任务?
解决方案
你的问题核心在于:await client.ws.get_data() 和 await client.ws.get_news() 会长期阻塞,导致循环中的 while not stop 检查根本无法执行——即使stop被设为True,任务也得等这两个方法返回后才会退出,完全达不到60秒后停止的要求。
正确的做法是利用asyncio的任务取消机制,直接在超时后终止未完成的任务,代码修改如下:
import asyncio async def watch_task1(): while True: await client.ws.get_data() async def watch_task2(): while True: await client.ws.get_news() async def main(): # 创建可跟踪的异步任务 task1 = asyncio.create_task(watch_task1()) task2 = asyncio.create_task(watch_task2()) try: # 等待任务完成,或60秒后超时 done, pending = await asyncio.wait([task1, task2], timeout=60) # 处理已完成的任务(可选) for task in done: try: result = task.result() print(f"任务完成结果: {result}") except Exception as e: print(f"任务执行出错: {e}") # 取消所有未完成的任务 for task in pending: task.cancel() # 等待任务响应取消,避免控制台警告 try: await task except asyncio.CancelledError: print(f"任务 {task.get_name()} 已被取消") except Exception as e: print(f"主流程出错: {e}") if __name__ == "__main__": asyncio.run(main())
关键说明:
- 移除全局
stop变量:不再依赖循环检查标记,而是直接通过task.cancel()强制终止任务,这是asyncio中停止长期阻塞任务的标准方式。 asyncio.wait的超时控制:timeout=60参数确保无论任务是否完成,60秒后都会返回已完成和未完成的任务列表。- 任务取消后的处理:调用
task.cancel()后需要await task,让任务有机会处理CancelledError并清理资源,避免控制台警告。
如果你的client.ws.get_data()支持中途中断(比如响应CancelledError),那么任务会立刻停止;如果底层不支持,可能需要等待其内部的阻塞操作结束,但这已经是asyncio框架下能做到的最及时的停止方式。
内容的提问来源于stack exchange,提问作者Nicolas Rey
相关产品推荐
相关产品推荐

