You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在部分任务耗时过久时正确关闭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())

关键说明:

  1. 移除全局stop变量:不再依赖循环检查标记,而是直接通过task.cancel()强制终止任务,这是asyncio中停止长期阻塞任务的标准方式。
  2. asyncio.wait的超时控制:timeout=60参数确保无论任务是否完成,60秒后都会返回已完成和未完成的任务列表。
  3. 任务取消后的处理:调用task.cancel()后需要await task,让任务有机会处理CancelledError并清理资源,避免控制台警告。

如果你的client.ws.get_data()支持中途中断(比如响应CancelledError),那么任务会立刻停止;如果底层不支持,可能需要等待其内部的阻塞操作结束,但这已经是asyncio框架下能做到的最及时的停止方式。

内容的提问来源于stack exchange,提问作者Nicolas Rey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 12:25:14