如何打印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
相关产品推荐
相关产品推荐

