# 三行速读
- 这章把慢任务从主循环剥离到后台执行槽位。
- 后台任务结果通过通知队列回流,主 loop 不被阻塞。
- 任务目标(s12)与运行槽位(s13)是两层不同状态。
# 先修知识
- 已理解 s12 的持久任务图。
- 熟悉线程 / 异步基础概念(至少知道 “后台执行” 含义)。
# 读完后你应该能做到(可检验清单)
# 本篇要解决什么
s12 解决 “任务目标持久化”,s13 解决 “慢任务执行不阻塞主循环”。很多真实命令需要几十秒甚至几分钟,若同步等待,整个系统吞吐会很差。
核心目标:让慢任务在后台跑,前台 loop 继续推进。
# 用一个类比先理解
像厨房出餐:
- 慢炖菜放后厨慢慢做;
- 前台继续接单、处理快菜;
- 炖好后通过叫号通知取餐。
后台任务 + 通知队列就是这个模式。
# 为什么这一步必须现在做
后续调度、自治队友都会依赖运行时执行槽位。没有后台机制,系统很容易被单个慢操作拖死。
# 关键代码怎么读
# 1) 通知队列
1 | class NotificationQueue: |
有优先级、有折叠(key)就能避免通知噪音泛滥。
# 2) 后台启动即返回
1 | def run(self, command: str) -> str: |
这个 “立即返回” 是吞吐提升的关键。
# 3) 完成后写日志并入通知
1 | def _execute(self, task_id: str, command: str): |
详细结果进文件,消息里只放预览,兼顾可追溯和上下文轻量。
# 4) 卡住任务检测
1 | def detect_stalled(self) -> list[str]: |
这让系统能主动发现 “长时间 running 但无进展” 的异常。
# 你可以怎么复现
- 把一个慢命令改为
background_run。 - 在主 loop 同时做其他任务。
- 下一轮 drain 通知,确认结果回流。
# 常见误区
- 误区 1:把后台任务当持久任务图本身。
- 误区 2:通知不清理,导致重复注入旧状态。
- 误区 3:没有输出落盘,失败后难复盘。
# 一句话总结
s13 把 “等待” 从主循环里移出去,让系统真正具备并行推进能力。
# 补充解读:后台槽位与通知回流细节
# A. Runtime 记录文件的意义
1 | RUNTIME_DIR = WORKDIR / ".runtime-tasks" |
.json 记录状态, .log 存完整输出。两者分开能兼顾状态查询和结果回放。
# B. _preview() 是上下文保护阀
1 | def _preview(self, output: str, limit: int = 500) -> str: |
它在限制通知体积,防止长日志回灌主上下文。
# C. check() 支持单任务与总览
这对调试很有用:既能看单个后台任务细节,也能看整体队列健康状态。
# D. drain_notifications() 的消费语义
1 | with self._lock: |
明确 “一次取走并清空”,防止重复处理。
# 进阶练习
- 为后台任务加 cancel 机制。
- 给 stalled 任务加自动告警消息。
- 测试多后台任务同时完成时的通知排序策略。
# 统一术语口径(本章)
Runtime Slot:后台执行中的运行时槽位记录。Notification Queue:后台结果回流主循环的通知队列。Stalled Task:超时未推进的可疑运行任务。
# 章节衔接(从易到难)
- 本章解决 “慢任务不阻塞”。
- 下一章
s14进入 “时间触发如何接入同一执行主线”。