设计一个快速的并发哈希表

2024 年 10 月 9 日,作者发布了papaya,这是一个用于 Rust 的快速且功能完备的并发哈希表。

  • 哲学:并发哈希表是一个被广泛研究的主题,有其优点和缺点。papaya 更关注读者,追求低延迟和可预测的延迟,适合读重的工作负载,同时有易于使用的 API 且不会死锁。
  • 基本设计:基本的RwLock<HashMap<K, V>>存在问题,分片可以改善可扩展性,但仍不理想。简单的无锁哈希表通过原子指针实现,可实现并发读写,但存在缓存问题。现代哈希表采用开放寻址法,papaya 也采用了类似的设计,并引入了元数据表来提高缓存效率。
  • 探测策略:开放寻址表的探测策略很重要,papaya 采用传统的二次探测策略,因为 SIMD 探测在并发环境中需要对齐,效率不高。
  • 负载因子:哈希表的负载因子决定何时需要重新调整大小,papaya 采用基于表容量的对数的最大探测限制来确定是否需要调整大小,避免了同步计数器的问题。
  • 删除:在开放寻址中,删除需要使用墓碑标记,并发删除会导致元数据表的同步问题。papaya 可以选择不允许删除后的条目被重用,以避免同步问题,但这会导致需要更频繁地调整大小。
  • 内存回收:在无锁环境中,并发删除的内存回收是一个难题,现有算法如危险指针和基于纪元的回收都有各自的优缺点。papaya 采用了 hyaline 算法,在退役批次时执行昂贵的跨线程检查,之后使用引用计数进行回收,提高了回收的可预测性。
  • 调整大小:哈希表需要在过满时调整大小,并发调整大小需要考虑很多权衡。papaya 实现了增量调整大小的算法,允许并发更新旧表和原子复制到新表,同时也支持阻塞调整大小。调整大小是 papaya 唯一不是无锁的情况,但采取了一些措施来减轻阻塞带来的问题。
  • 额外功能:papaya 有一些独特的功能,如暴露了许多原子操作,允许执行复杂的操作;有异步支持,通过pinpin_owned来实现,pin_owned是可发送和同步的,但创建成本较高。
  • 比较:与其他并发哈希表 crate 相比,papaya 在读取吞吐量和可预测延迟方面表现较好,异步支持也很独特。但对于写重的工作负载,dashmap 可能更合适;对于非常读重的工作负载,evmap 可能是更好的选择,但它是最终一致的。其他 crate 如 scc 和 leapfrog 也有各自的特点和局限性。

总之,papaya 是一个功能强大的并发哈希表,在读取性能和可预测性方面表现出色,同时具有一些独特的功能,但在不同的工作负载下,可能需要选择其他 crate。

阅读 18
0 条评论