mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-09-27 21:03:16 +00:00
## 问题
StageHost.ToolDef 返回 &def —— 一次**结构体拷贝**:3 个 string + 2 个 map 头
+ 2 个 bool + Cleaner 函数指针。
而 toolParallelSafe 在**每批**并发判据里对每个工具各调一次:
batchRunnable 遍历 PendingTools → toolParallelSafe(tc.Name)。
1000 并发批次 = 1000 次结构体拷贝,全在判定阶段(执行之前)。
不是"逃逸漏洞"(Go 1.22+ 循环变量每轮独立,go.mod 是 1.25),纯粹是白拷贝。
## 修法
ToolDef 保留 —— 它要给需要完整声明的调用方(Cleaner、Parameters 校验),
返回副本也是**有意**的(ToolDef 里有 map 与函数指针,交出内部元素会把
可变引用漏出去)。
新增免拷贝查询,热路径专用:
ConcurrencySafeOf(name) (safe, found bool) // 只读 ParallelSafe && !Serial
NoMemoryOf(name) (v, found bool)
HasTool(name) bool
全部在持 RLock 下走同一个 findLocked。
`toolParallelSafe` 切到 ConcurrencySafeOf。语义完全等价 —— 两者都算
`ParallelSafe && !Serial`,只差一次拷贝。
## 判据(两个都防"优化悄悄改了语义")
- TestNoCopyQueriesMatchToolDef 7 种声明组合(plain / parallel / serial /
both / nomem / all / serial_nomem)下,免拷贝查询与 ToolDef(...).字段
**逐字段等价**;不存在的工具三态一致(false/false/true)。
★ 这类优化最危险的失败模式就是语义漂移:并发判据若读错字段,
能并发的批次会**悄悄退化成串行** —— 没有任何报错,只表现为"变慢了"。
所以判据必须逐个组合比对,而不是只测一个典型值。
- TestNoCopyQueriesConcurrent 32 goroutine × 50 工具并发查询,
-race 无竞态且结果与串行一致。
回归:go build ./... 通过;go test ./internal/... 全绿;
go test -race ./internal/agent/core 通过。