56 个版本 (34 个稳定版)
11.0.0-alpha.7 | 2020 年 12 月 21 日 |
---|---|
11.0.0-alpha.2 | 2020 年 11 月 29 日 |
11.0.0-alpha.1 | 2020 年 6 月 3 日 |
10.0.2 | 2020 年 5 月 11 日 |
0.4.0 | 2017 年 3 月 31 日 |
#452 in 并发
5,985 每月下载量
用于 22 个 Crates (16 个直接使用)
89KB
1.5K SLoC
一个无锁、最终一致的并发多值映射。
此映射实现允许读取和写入完全并行执行,没有隐式同步开销。读取永远不会在其关键路径上获取锁,写入也是如此,假设有一个单写入者(使用 Mutex
可以实现多写入者),这在竞争条件下显著提高了性能。它由并发原语 left-right
支持。
此模块暴露的权衡是最终一致性:除了跟随显式同步之外,写入对读取者不可见。具体来说,读者只能看到写入者在最后一次调用 WriteHandle::flush
之前的操作。这允许写入者决定它们愿意让读取变得多旧。它们可以在每次写入后刷新映射以模拟常规并发 HashMap
,或者它们可以偶尔刷新以减少同步开销,但以读取过时为代价。
对于读取密集型的工作负载,此模块使用的方案特别有用。写入者可以承受在每次写入后刷新,这提供了最新的读取,而读取者保持快速,因为它们永远不需要获取锁。
此映射是多值的,这意味着每个键映射到一个 集合 的值。这通过为每个值添加一层通过 Vec
的间接层来增加一些内存成本,但允许更高级的使用。这个选择是因为不可能在这个映射的语义之上模拟这种功能(想想看——操作日志将包含什么?)。
为了便于更高级的使用场景,这两个映射也携带一些可定制的元信息。写入者可以随意更新这些信息,当刷新发生时,当前的元信息也会对读取者可见。例如,这可以用来指示刷新发生的时间。
性能
这些基准测试已经过时,但传达了正确的观点。希望我很快有机会再次更新它们。
我在一个带有英特尔(R) Xeon(R) CPU E5-2660 v3 @ 2.60GHz CPU的40核机器上,使用位于benchmark/目录下的二进制文件,对evmap进行了基准测试,并与由读写锁保护的Rust标准库中的HashMap
进行了比较,以及与chashmap——一个提供基于桶级别多读锁的“并发哈希表”的crate进行了比较。
基准测试运行了一组紧密循环中的读线程和写线程,每个线程分别对映射中的随机键进行读取或写入。下面提供了均匀分布和偏斜分布的结果。该基准测试测量随着读者和作者数量的增加,每秒平均读取和写入次数。
初步结果表明,在竞争条件下,evmap
的性能良好,特别是在读取方面。这个基准测试代表了evmap
的最坏情况使用,其中每个写入都会执行一个refresh
。如果映射刷新得更少,性能会提高(见底部图形)。
依赖关系
~0.2–27MB
~340K SLoC