1 简介
原生 map 类型不是线程安全的,尤其在高并发或大批量写入场景下,如果多个 goroutine 同时对同一 map 执行写操作(或读写混合),往往会导致程序 panic、写入失败或不确定行为。
Go 1.24 中引入了 Swiss Table 作为 map 数据类型的新底层实现,这是 Go 语言发展中的一个重要改进。
这个实现借鉴了现代编程语言(如 C++ 和 Rust)中的哈希表优化技术,尤其是来自 Google 的 SwissTable 实现(在 C++ 的 absl::flat_hash_map 和 Rust 的 HashMap 中应用)。

这次更改提升了性能、减少了内存使用,并提高了并发场景下的稳定性。
Swiss Table(或 SwissMap)是一种高度优化的哈希表实现,在 Go 1.24 中被用作默认的 Map 实现。 这一变化显著提高了 Go 内置map类型的性能和内存效率。
2 map 仍然是非线程安全类型
Go 的原生 map 不是同步容器:当并发写入或读写时,行为未定义,极易触发运行时 panic,如 "concurrent map writes" 或 "concurrent map read and map write"
比如多个写操作并发执行,会出现数据竞态,甚至内存崩溃。
- 常见解决方案:
使用显式同步机制,如 sync.Mutex / sync.RWMutex;
使用标准库提供的线程安全 map:sync.Map;
使用分片 map(sharding)实现更高性能并发写入(如多个桶分别加锁)
- Go 1.24 是否改进了 map 并发写入的稳定性
Go 1.24 并没有使原生 map 变为线程安全。
即便 Go 1.24 引入了新的 map 实现(Swiss Table),其仍不支持多个 goroutine 无同步地写同一个 map。
任何未加锁的并发写入仍将产生竞态和 panic,不属于 Go 1.24 的改进范围。
- 为什么常在大批量赋值时"失败"
高并发写入时 map 的内部结构会扩容或重组,如果没有同步,写入就无法保证一致性,最终触发失败。
- Go 1.24 面对 map 的实际改进措施 ✔
虽然 不针对并发安全做改动,Go 1.24 对 map 的内部性能和扩容机制做了重要优化:
3 基于 Swiss Table 的重构
默认从 Go 1.24 起,map 采用更现代的 Swiss Table 哈希表结构,提高插入/查找效率,尤其在大规模 map 中性能优势显著:插入提升约 30--35%,迭代速度提升 10--60%
-
对分散 key 操作的优化 对分布在 不同 key 集 的写入操作支持更高并行效率,减少扩容冲突及缓存抖动
-
Maps.Clone 性能回归问题
新版swiss table使用组内探测实现开发地址探测方法,它有以下主要特点:
-
每个探测"步骤"检查一个小的、固定大小的槽组(如 8 个槽)。
-
每个槽有一个 控制字节,可以提前并行比较,快速淘汰不匹配的槽。
-
探测顺序通过类似线性偏移 + 再哈希调整的方式继续。

引入 Swiss Table 后,maps.Clone 性能比自定义 for-range 拷贝略差,引发社区关注,但未被认作严重问题
4 Go 关于并发 map 安全的应对思路与实践
-
- 继续明确 map 的线程不安全性
Go 语言依旧明确保持 map 属于非线程安全类型,鼓励开发者显式管理并发安全。
-
- 提供 sync.Map 标准组件
官方提供 sync.Map 作为线程安全的 map,底层优化以减少锁竞争,适用于读多写少场景。
-
- 社区探索高性能并发 Map 实现
一些第三方库(如 cmap 等)采用分片 + fine-grained locking 的方法提高写安全性及性能。
-
- 提升 map 内部实现性能
Go 1.24 通过改进内核结构(Swiss Table)提升整体 map 操作性能,间接降低扩容阶段的竞争过程复杂度,但仍需开发者自行同步。
5 小结
arduino
功能 Go ≤1.23 Go 1.24
原生 map 并发写安全 ❌ 非线程安全,易崩溃 ❌ 非线程安全
map 结构效率 原始哈希表实现 Swiss Table 重构,插入/迭代效率显著提升
支持并行写的能力 扩容冲突多,延迟高 扩容流程更高效,对分散写支持更好
性能改进方向 --- 插入性能提升 30%+,迭代速度更快
实践建议:千万不要在多个 goroutine 中无锁地写同一个 map。
若并发量大,请考虑:
dart
sync.Map;
自定义分片 map;
使用 sync.Mutex/RWMutex 保护 map。
对大批量赋值的性能敏感应用,可以测试 Go 1.24 对比旧版在你的使用场景下的 map 行为。
使用 -race 工具检测竞态问题,确保写入前后行为正确。
Go 1.24 并没有变更 map 的线程安全属性------原生 map 依旧不是线程安全,并发写入必须同步处理。
Go 团队在该版本通过 Swiss Table 重构 极大提升了 map 的性能,降低扩容冲突、提升大规模使用场景的效率。
并发 map 使用安全依然由使用者负责:采取锁或线程安全结构是唯一可靠的方法。
Swiss Table in Go 的主要特点和优势:
arduino
元数据存储:
与以前的 Go map 实现不同,以前的实现中元数据与键值对一起存储在每个 bucket 中,而 Swiss Tables 将元数据单独存储在紧凑的"控制字节"数组中。 由于元数据紧密打包,这可以更快地扫描潜在匹配项并提高缓存效率。
使用元数据的探针序列:
在搜索键时,Swiss Tables 首先扫描元数据数组,快速过滤掉不相关的存储桶,然后再执行完整的键比较。 此过程类似于 Go 的旧版 tophash 系统,但由于单独的元数据存储,缓存效率更高。
缓存友好组:
Swiss Tables 将数据组织成小而密集的组,而不是依赖于相互关联的溢出链。 这减少了"指针追逐",并使相关数据在内存中保持更紧密的联系,从而提高读写速度。
高效的插入和查找:
单独的元数据和基于组的组织允许在插入过程中更快地识别空槽,并通过首先扫描元数据来实现更快的查找。
性能改进:
通过减少缓存未命中、改善内存布局和优化碰撞处理,瑞士表可显著提高性能,特别是对于大型地图而言。
本质上,Go 在 1.24 版本中采用 Swiss Tables 代表了其核心map功能的重大增强,从而带来了更快、更节省内存的应用程序。
参考:
arduino
https://go.dev/blog/swisstable