HARNESS / 代理工程下载 EPUB ↓
15 / 32

第十四章:并发、顺序和取消是一组三方约定

14.1 执行顺序与提交顺序可以不同

模型依次提出读取 A、B、C,磁盘可能按 B、C、A 完成。界面可以即时显示真实完成事件,模型历史却仍按 A、B、C 的调用顺序接收结果。这样既能提高吞吐,也让后续上下文稳定。

Pi 的并行工具逻辑先准备调用,执行完成后发事件,再按原槽位整理结果。DeepSeek 的调度器则明确说明并发执行与模型顺序提交的关系。它们为这项区分提供了具体例子。Pi · agent-loop.ts L644–658 DeepSeek Harness · tool-calls.ts L58–72

14.2 并发安全是语义,不是工具类别

读取通常比写入容易并行,但并不是所有读取都无共享状态。例如某工具读取并推进一个游标,或在执行前后更新会话配置,它就可能需要独占。两个写操作若目标独立,理论上也可能安全,但需要具体资源级协议支持。

DeepSeek 的注册表在无法确认安全时回退独占。Codex 的工具运行时持有共享读写锁状态,具体调用怎样取得并行资格还要继续沿分派代码阅读。不能仅凭看见一个锁,就宣称所有工具具有相同调度行为。DeepSeek Harness · index.ts L1309–1323 Codex · parallel.rs L49–63

14.3 屏障保证什么

假设调用序列是读取 A、读取 B、修改 C、读取 C。屏障调度可以先并行前两个读取,等待它们完成,再执行修改,最后开始读取 C。它保证的是这一批调用的相对约束,不自动保证其他进程不会修改 C。

如果模型把“读取 C”与“修改 C”放在同一批中,宿主必须依据工具契约或依赖表示决定是否允许。不要默认模型给出的列表顺序已经完整表达资源依赖,也不要仅用一个并发数限制代替语义屏障。

14.4 取消需要停止启动、通知运行和完成收尾

取消不是一个布尔值改变后所有工作瞬间消失。调度器首先应停止启动新工作;已启动操作需要收到信号;最后还要等待它们收尾,并保存已知结果。若某个操作忽略信号,就不能诚实地宣布它已停止。

Claude 的执行器区分兄弟工具错误与用户中断等原因,DeepSeek 的调度器说明中断时停止补充并等待已启动调用。原因分类与清理协议,决定取消后还能安全做什么。Claude Code 2.1.88 提取快照 · StreamingToolExecutor.ts L38–52 DeepSeek Harness · tool-calls.ts L58–72

随书实验只在合作边界检查 threading.Event,不声称能强制停止任意文件系统调用。因为没有远程执行和通用子进程,这个限制容易观察;扩展 Shell 工具时就必须设计进程组终止、输出排空和句柄失效机制。

14.5 哪些指标比并发数有用

记录排队时间、开始到完成时间、等待有序提交的时间和取消清理时间。一个后面的工具虽然早早完成,却因为前面的慢调用阻塞提交,这与工具本身慢是两种问题。

练习:让 B 比 A 更快完成,断言 UI 事件可以先出现 B,而模型结果仍按 A、B。再加入一个写入屏障。测试应检查真实调度关系,不只断言最终结果数组长度。

非官方学习读物 · 固定源码快照 · 原始代码保留各自许可。GitHub · 源码依据 · 实验代码