58 次发布

0.5.3 2024 年 8 月 16 日
0.5.2 2024 年 6 月 17 日
0.5.1 2024 年 5 月 30 日
0.5.0 2024 年 3 月 19 日
0.1.2 2018 年 10 月 26 日

#11缓存 类别中排名

Download history 1130/week @ 2024-05-04 1742/week @ 2024-05-11 1409/week @ 2024-05-18 1673/week @ 2024-05-25 1586/week @ 2024-06-01 2054/week @ 2024-06-08 1735/week @ 2024-06-15 1625/week @ 2024-06-22 1426/week @ 2024-06-29 1400/week @ 2024-07-06 1515/week @ 2024-07-13 2084/week @ 2024-07-20 1831/week @ 2024-07-27 1162/week @ 2024-08-03 1376/week @ 2024-08-10 1284/week @ 2024-08-17

6,320 每月下载量
6 Crates 中使用 (直接使用 4 个)

MPL-2.0 许可证

1MB
17K SLoC

Concread

为 Rust 开发的并发可读数据结构。

并发可读通常称为写时复制(Copy-On-Write)、多版本并发控制(Multi-Version-Concurrency-Control)。

这些结构允许在事务中进行多个读取操作的同时,单个写操作可以执行。读取者保证读取期间内容保持不变,且读取者不会阻塞写操作。写操作是序列化的,就像互斥锁一样。

此库包含并发可读的 Cell 类型以及 Map/Cache 类型。

何时使用这些?

您可以使用这些来代替 RwLock,并可能观察到并行吞吐量的提高。

最佳用途是代替互斥锁/rwlock,其中读取者存在非平凡的时间。

例如,如果您有一个 RwLock,在获取锁、数据更改或读取后立即释放,这可能不会帮助您。

然而,如果您有一个需要长时间保持读锁的 RwLock,写操作将开始停滞 - 或者相反,写操作将导致读取者阻塞并等待写操作完成。

并发可读避免了这一点,因为读取者永远不会阻塞读取者/写操作,写操作也永远不会阻塞或阻塞读取者。这意味着您通过减少停滞而获得并行吞吐量的提升。

此库还包括并发可读的 BTreeMap、HashMap 和自适应替换缓存。当您的 Cell 中至少有 512 字节的数据时,这些最适用,因为它们只会复制更新所需的内容。

如果您不需要键排序,那么 HashMap 可能是大多数应用程序的最佳选择。

什么是并发可读?

在多线程应用程序中,通常需要在线程之间共享数据。在共享这些数据时,存在多种策略 - 原子操作用于单个整数的读取,互斥锁用于单线程访问,RwLock 用于多个读取者或一个写操作,直到无锁(Lock-Free)允许对队列进行多个读取和写入。

无锁技术虽然有其局限性,因为它基于原子操作。这意味着它每次只能持续更新少量数据。这也意味着你没有事务性操作。虽然这对于队列来说很好,但对于需要操作过程中状态一致性的树或哈希表来说则不是很好。在存在无锁树的地方,它们具有这样一个特性:在更新树的时候,所有其他读者都能立即看到这些变化。你的数据可能会在你察觉之前就改变了。

另一方面,互斥锁和读写锁允许保护更复杂的结构。它们保证了所有读者总是看到相同的数据,并且写者是唯一的写者。但是,它们会导致等待访问它们的线程阻塞。例如,如果读者不会让步,读写锁可能会导致很大的延迟,如果操作系统的优先级偏向于其他进程,可能会造成读写者饥饿。

并发可读结构位于这两个点之间。它们提供多个并发读者,具有事务性操作,同时允许单个写者同时进行。

这是通过在写者修改之前复制内部数据来实现的。这允许读者访问旧数据,而不对其进行修改,并允许写者在提交之前就地更改数据。一旦新数据被存储,旧读者将继续访问他们的旧数据——新读者将看到新数据。

这是一个时间和空间的权衡,使用更多的内存来实现更好的并行行为。

安全性

这个库经过了广泛的测试,并在miri(一个Rust未定义行为检查器)的测试中通过。但是,如果你发现任何问题,请告诉我们,以便我们可以修复它!

使用miri或nightly上的asan进行检查

# Follow the miri readme setup steps
cargo clean && MIRIFLAGS="-Zmiri-disable-isolation -Zmiri-disable-stacked-borrows" cargo miri test
RUSTC_FLAGS="-Z sanitizer=address" cargo test

注意:Miri需要禁用隔离,以便在ARC缓存通道中使用clock monotonic。

单指令多数据(SIMD)

如果你使用的是nightly编译器,ARC支持SIMD。要使用它,你需要编译

RUSTFLAGS="-C target-feature=+avx2,+avx" cargo ... --features=concread/simd_support

贡献

请打开一个问题,pr或通过电子邮件直接联系我(见github)

依赖项

~1.2–8.5MB
~50K SLoC