主要观点:
- 许多“脚本”语言使用哈希表作为默认的关联数据结构,但哈希表有很多问题,如易受哈希洪水攻击、迭代顺序不确定、插入时可能重新哈希导致最坏情况延迟大、在 wasm 目标上难以避免大分配的碎片化、向量指令受限等,而有序数据结构如 B 树没有这些缺点,但通常比哈希表慢。
- 通过微基准测试比较了 Rust 的
std::collections::HashMap
、std::collections::BTreeMap
,Zig 的std.HashMap
(使用 siphash 和 wyhash)以及作者自己的bptree
,发现哈希表在连续多次查找时受益于推测执行,而 B 树则没有,并且不同的测试场景(如整数键、字符串键、wasm 环境等)下性能表现不同。 - 实现了 B 树和 B+树,发现对于插入/查找操作两者区别不大,更喜欢 B+树的简单实现;对 Rust 的 BTreeMap 进行了一些优化,如固定节点大小、使用
less_than
进行搜索等,但线性搜索在大多数基准测试中仍然更快。 - 总体认为进一步探索 B 树不值得,将继续使用哈希表,但留下了一些未探索的想法,如将哈希函数作为编译器的稳定 API 的一部分、使用哈希数组映射 trie 等。
关键信息:
- 哈希表的缺点:易受哈希洪水攻击、迭代顺序不确定、插入时可能重新哈希导致最坏情况延迟大、在 wasm 目标上难以避免大分配的碎片化、向量指令受限。
- 不同数据结构的性能表现:在连续多次查找时哈希表受益于推测执行,B 树则没有;不同测试场景下性能不同,如整数键时 B 树和哈希表差异不大,字符串键时 B 树性能受影响较大,wasm 环境下性能表现也有所不同。
- 对 Rust 的 BTreeMap 的优化:固定节点大小为 512 字节、使用
less_than
进行搜索、尝试不同的二进制搜索等。 - 空间使用情况:预计 B 树的空间使用情况更差,随机键时典型节点占用率为 50%,而 Zig 哈希表为 80%。
重要细节:
- 微基准测试的不同版本及结果,如
lookup_hit_all
、lookup_hit_one
、lookup_hit_batch
、lookup_hit_chain
等,不同版本下哈希表和 B 树的性能表现差异。 - 不同环境下的测试情况,如在 wasm 环境下哈希函数和表扫描都不生成向量指令。
- 实验使用的工具和环境:rustc 1.77.2、zig 0.14.0-dev.1694+3b465ebec、wasmtime-cli 20.0.2,运行在 intel i7-1260P 上,关闭效率核心、设置缩放调节器为性能、禁用涡轮模式和 ASLR 等。
- 留下的未探索想法,如将哈希函数作为编译器的稳定 API 的一部分、使用哈希数组映射 trie 等。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。