在 Go 1.24 里,sync.Map 的内部实现不再是“只读快照 + 脏表”那套组合拳,而是切到了一个并发哈希前缀树(HashTrieMap)上,这套树形结构最先在 unique 包里测试,后来直接拿来当底层实现,读写都在节点级别并发搞定,锁冲突少了,更自然;如果真遇到兼容问题,还能通过 GOEXPERIMENT=nosynchashtriemap 回退到旧版 。
旧版 sync.Map
- 老版
sync.Map核心由两个 map 组成:一个只读快照(readOnly),一个写时用的“脏表”(dirty) 。 - 读操作先看只读快照,命中就原子返回;若快照没命中且标记了脏表,再加锁去脏表里找,必要时把脏表整体合并到快照里 。
- 写操作都先落到脏表,只有当“未命中”次数攒够了,才触发脏表升级成新快照 。
新版 sync.Map
- Go 1.24 直接把底层换成 并发哈希前缀树(
HashTrieMap),节点上用原子操作和小范围锁,读写都在树节点级别并行,不再分快照/脏表两块 。 - 新结构抛弃了双表设计,用树形哈希前缀把键分层存储,自动并发,对写冲突友好 。
- 如果有兼容顾虑,设置
GOEXPERIMENT=nosynchashtriemap就能退回到老版实现 。 - 由于接口没变,老代码直接跑在新实现上就能享受底层升级,无需任何改动 。
核心变化
- 旧版:双 map 设计,读走快照、写进脏表,加锁+升级;
- 新版:HashTrieMap 树形结构,节点级原子操作/小范围锁,读写都并行;
- 兼容兜底:环境变量一键切回旧实现;