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

如何打印trio.Nursery实例中未退出child_tasks的状态及相关疑问

Trio Nursery 任务状态查看与核心机制疑问解答

一、查看Nursery子任务状态(含未退出任务)

要打印nursery.child_tasks中所有任务的状态,尤其是未退出的任务,直接遍历该集合并访问任务的status属性即可。trio.TaskStatus枚举定义了任务的所有状态(如RUNNING、FINISHED、FAILED、CANCELLED等)。

示例代码:

import trio

async def sample_task(delay):
    await trio.sleep(delay)

async def monitor_nursery(nursery):
    # 遍历所有子任务
    for task in nursery.child_tasks:
        # 打印任务ID、状态,标记未退出任务
        is_running = task.status not in (trio.TaskStatus.FINISHED, trio.TaskStatus.FAILED, trio.TaskStatus.CANCELLED)
        print(f"任务ID: {task.id}, 状态: {task.status.name}, 未退出: {is_running}")

async def main():
    async with trio.Nursery() as nursery:
        nursery.start_soon(sample_task, 2)
        nursery.start_soon(sample_task, 5)
        # 启动监控任务
        await monitor_nursery(nursery)

if __name__ == "__main__":
    trio.run(main)

注:如果要持续监控未退出任务,可以在循环中加入await trio.sleep(0.1)之类的调度点,避免阻塞其他任务。

二、核心机制疑问解答

1. 嵌套子任务的作用与_nested_child_finished()的用途

嵌套子任务对应嵌套Nursery的场景:当你在一个已启动的任务内部再创建并使用async with trio.Nursery()时,这个嵌套Nursery启动的任务就是外层Nursery的嵌套子任务。

  • _child_finished()仅处理当前Nursery直接启动的任务:当直接子任务完成(正常或异常),会被从child_tasks中移除。
  • _nested_child_finished()则负责跟踪嵌套Nursery的任务完成:外层Nursery需要等待直接子任务的所有嵌套子任务都完成,才会认为这个直接子任务真正“结束”。比如你在一个子任务里启动了嵌套Nursery并跑了3个任务,只有这3个嵌套任务都完成后,外层Nursery才会通过_nested_child_finished()的逻辑,标记对应的直接子任务为可清理状态,最终通过_child_finished()移除。

简单说,这个机制是为了保证Nursery能等待所有层级的子任务完成,而不是只等待自己直接启动的那一层。

2. 任务失败到全部完成的时间窗口与活跃任务状态

由于Trio是协作式调度,任务只有在执行到await、yield等调度点时才会响应取消信号,因此从某个任务抛出异常到所有任务完成,会存在一个时间窗口,其中会出现两种“活跃”状态的任务:

  • “已失败,异常已捕获”:指抛出异常的那个任务本身,它已经终止运行,异常被Nursery的异常处理逻辑捕获(此时可能还在等待其他任务响应取消,尚未向上传播异常),任务状态为FAILED。
  • “正在运行,尚未处理Canceled异常”:其他未到达调度点的任务,它们还在正常执行代码,没有触发取消逻辑,状态仍为RUNNING。只有当这些任务执行到下一个调度点时,才会收到Canceled异常并开始处理终止流程。

内容的提问来源于stack exchange,提问作者some bits flipped

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 12:24:46