6 哈希
2 分钟阅读
译文 · 基于 The Rust Performance Book
哈希
HashSet 和 HashMap 是两种广泛使用的类型,有办法使它们更快。
替代哈希算法
默认哈希算法未作规定,但截至撰写时,默认算法是称为 SipHash 1-3 的算法。该算法质量高——提供强大的防碰撞保护——但相对较慢,尤其是对整数等短键而言。
如果性能分析显示哈希是热点,且 HashDoS 攻击对你的应用不构成威胁,使用具有更快哈希算法的哈希表可以带来显著的速度提升。
rustc-hash提供FxHashSet和FxHashMap类型,可作为HashSet和HashMap的直接替代。其哈希算法质量较低但非常快,尤其对整数键而言,在 rustc 内部的表现优于所有其他哈希算法。(fxhash是同一算法和类型的较旧、维护较少的实现。)fnv提供FnvHashSet和FnvHashMap类型。其哈希算法质量高于rustc-hash,但稍慢一些。ahash提供AHashSet和AHashMap。其哈希算法可利用部分处理器上可用的 AES 指令支持。
如果哈希性能对你的程序很重要,值得尝试多种替代方案。例如,在 rustc 中观察到以下结果。
如果你决定普遍使用某种替代方案,例如 FxHashSet/FxHashMap,很容易在某些地方误用 HashSet/HashMap。你可以使用 Clippy来避免此问题。
有些类型不需要哈希。例如,你可能有一个包装整数的新类型,且整数值是随机的或接近随机的。对于此类类型,哈希值的分布与值本身的分布不会有太大差异。在这种情况下,nohash_hasher crate 可能很有用。
哈希函数设计是一个复杂的话题,超出了本书的范围。ahash 文档中有很好的讨论。
按字节哈希
当你用 #[derive(Hash)] 标注类型时,生成的 hash 方法会分别哈希每个字段。对于某些哈希函数,将类型转换为原始字节并将字节作为流进行哈希可能更快。这对于满足某些属性(例如没有填充字节)的类型是可行的。
zerocopy 和 bytemuck crate 都提供 #[derive(ByteHash)] 宏,生成执行此类按字节哈希的 hash 方法。derive_hash_fast crate 的 README 对此技术有更多细节。
这是一项高级技术,性能影响高度依赖于哈希函数和被哈希类型的确切结构。请仔细测量。