Reuse 不是一个通用 Cache
一句话
Pysolate 的 reuse 不是一个万能缓存:有的保存完成值,有的合并正在进行的计算,有的复用 typed bytes、初始化工作、内存页或文件 lineage;每类对象都有独立 owner、lifetime、identity 和 cleanup。
先看一个例子
一间实验室想减少重复工作,可以做几件完全不同的事:
- 保存上次实验的最终报告;
- 十个人同时提交相同实验时,只让一个人计算,其他人等待;
- 保存一份经过验证的数据文件,给每个学生复制一份;
- 预先启动一台尚未被任何学生使用的机器;
- 从相同项目目录复制出多个私有修改分支。
这些都可以叫“复用”,但把它们塞进同一个 cache API 会掩盖最重要的问题:到底复用了什么,谁能关闭它,以及旧权限有没有被带过来。
真实机制
| 机制 | 复用的对象 | Owner 与 lifetime | 绝不自动复用 |
|---|---|---|---|
| Whole-Run memoization | exact Invocation 的 canonical 完成结果 | Host agentfunction.Store,保留至显式 evict 或目录清理 | 旧 Guest、receipt、live I/O authority;容量上限只拒绝新 publication,不自动 eviction |
| Single-flight | 同一 identity 正在进行的一次 computation | Host FlightGroup,leader 完成后 entry 删除 | 完成值留存、后续 sequential hit |
| Typed result/materialization | bounded descriptor 与 immutable body | Run-private resultblob.Store 和 one-shot lease | producer heap、pointer、generic Python object |
| Prepared runtime/image | 从未服务过的 initialized module,或 sealed linear-memory baseline | Wazero Engine;普通 slot one-shot,COW image 随 Engine | Python frame、workflow continuation、结果 |
| Prepared Family | 一份 validated bounded NumPy input;COW lane 另有 sealed image/page lineage | PreparedFamily 到显式 Close;member runner single-use | Member 的 Plan、Broker、Invocation、workspace、Python mutation 或 result;private-copy 仍逐 Guest prepare |
| Workspace lineage/attempt | parent identity 与私有目录副本 | Workspace Manager、Lease、Branch/Attempt | filesystem merge、Guest 或 capability state |
| Prepared-data staging | 一次授权读取产生的 Run-private typed object | StagedObject 到 claim/orphan/cancel/reject | durable cross-Run dataset cache |
| Proof/identity | canonical digest 与 opaque qualification | 对应 Host contract owner | Authority、结果 bytes、共享 backing memory |
Pure source-derived execution patch 没有列成 reuse primitive,因为它不保存或共享跨 Run 的对象:它只把 exact original source/AST 变成一次受 identity 约束的 derived execution selection。它不是 memoization、single-flight、prepared runtime 或 staged object,也不携带旧 authority、receipt 或 result。
Whole-Run memoization 和 single-flight 最容易混淆。前者在计算成功后保留 result,使之后的相同调用可以命中;后者只让并发 waiter 共享一次正在运行的 leader,完成后不留下 value。两者可独立开关。
Typed result 会复制并验证 body,给每个 fresh consumer 重新 materialize 私有对象。Prepared runtime/private-COW 可以复用已准备的 memory baseline 与部分初始化成果;每个 COW consumer 仍要 instantiate 新 module,并执行必要的 _initialize。Workspace reuse 则保留文件内容或 lineage;当前 Branch/Attempt 仍做完整目录 copy。
Prepared Family 是表中的一种显式、有限 multi-consumer owner,不是通用 cache;它的 input/image 与 per-member authority 边界集中在第 23、24 篇解释。
每类机制都重新检查自己的 identity 和 admission。Cache key 或 digest 只证明 canonical bytes/inputs 相等,不能携带旧 Plan、receipt 或 external-effect authority。Miss 或 mechanism unavailable 可以按各自合同选择 ordinary fresh path;identity drift、已选中机制的初始化错误或容量限制则可能拒绝 publication 或 fail closed。任何情况都不能偷偷使用仍持有旧状态的解释器。
为什么重要
技术上: 对象分类让 copy/alias、privacy partition、close authority 和失败语义可检查。关闭 typed body store、释放 COW mapping、evict result 和 discard workspace attempt 是四种不同操作。
产品和业务上: 团队可以针对真实成本选择机制:并发重复多时用 single-flight,纯计算重复多时才考虑 memoization,启动昂贵时用 prepared runtime。没有经济收益的机制可以保持关闭,而不影响 fresh execution 的语义基线。
不能推出什么
- Cache hit 不会恢复旧执行的 authority、receipt 或 effect transcript。
- Typed result 当前不是 generic object ABI;private-COW 也不是 result cache。
- 某个机制在测试中正确,不等于它在生产 workload 中达到 break-even。
- Whole-Run Store 当前没有统一 TTL/Close policy;已有 entry 依赖显式 evict 或目录清理,容量限制只控制新的 publication。
术语卡
- Memoization:保存已完成的 canonical 结果供后续调用命中。
- Single-flight:把并发的相同 in-flight work 合并到一个 leader。
- Materialization:从受限 descriptor/body 为 consumer 重建私有值。
- Prepared runtime:预先完成部分初始化、等待一次服务的 runtime 对象。
- Reuse identity:判断两个复用请求是否属于同一对象的 canonical binding。
继续阅读
- 前置:Prepared data 与一次性 object claim
- 后续:Prepared runtime 与 private-COW、Prepared Family 到底共享什么
- 说明文档:
implementation/05-reuse-taxonomy.md、design/abstractions-patterns-and-tradeoffs.md - 源码 owner:
runtime/agentfunction/cache.go、runtime/agentfunction/singleflight.go、runtime/resultblob/store.go、runtime/engine/wazero/prepared_family.go