#thread #channel #async-channel #wait #free #swapping #block

nightly cupchan

两个线程之间简单的异步覆盖通道,通过交换杯子实现无需等待和阻塞

3 个版本

0.1.2 2022 年 3 月 20 日
0.1.1 2022 年 3 月 20 日
0.1.0 2022 年 3 月 19 日

#716 in 并发

LGPL-2.1 AND MIT AND BSD-2-Clause

17KB
336

cupchan

docs.rs crates.io

是的,cup-chan,请帮我交换杯子 uwu

两个线程之间简单的异步覆盖通道,通过交换杯子实现无需等待和阻塞

这个项目源于我需要在一个线程上懒更新另一个线程上的数据,而不必等待互斥锁。

工作原理

这个 crate 通过三个可交换标签的“杯子”来实现无等待和阻塞的通道。每个杯子都标记为具有特定的目的,即写入、存储和读取。(此标记存储在原子 u8 中)。

写入线程可以访问写入杯子,读取线程可以访问标记为读取的杯子。一旦写入线程准备好更新读取线程,它就会向自己的杯子写入并调用 flush(),该操作会切换写入和存储标记。(这是一个使用 fetch_update 的单个原子操作)。

例如,杯子可能开始如下所示:<W><S><R>

写入线程写入一些内容:<S><W><R> - 写入标记已与存储标记交换,并设置了一个标志来告知读取线程存储已被更新。

读取线程想要检查数据,因此它会检查更新标志。如果已设置,则读取线程将存储和读取标记交换。然后读取线程检查读取杯子中的数据。

标记系统确保写入和读取线程永远不会同时访问同一个杯子。

以下是所有可能的杯子状态及其之间关系的图表: quiver.

测试

此crate已通过loom验证。

运行测试

$ cargo test
$ RUSTFLAGS="--cfg loom" cargo test --test loom_test --release

备注:如果使用LOOM标志,在更改代码后请确保清除检查点文件。

基准测试

每个基准测试代表发送了5_000个64位整数。

test tests::bench_crossbeam_chan_cap_10 ... bench:     227,330 ns/iter (+/- 53,862)
test tests::bench_crossbeam_chan_cap_3  ... bench:     406,431 ns/iter (+/- 73,856)
test tests::bench_cupchan_greedy        ... bench:     404,699 ns/iter (+/- 36,296)
test tests::bench_cupchan_lazy          ... bench:     102,177 ns/iter (+/- 10,770)
test tests::bench_flume_chan            ... bench:     725,894 ns/iter (+/- 107,237)

此crate在其预期功能(懒加载地流式传输更新值)上比crossbeam和flume更快。如果您只需要尽可能快地移动和消耗数据,请使用这些crate。

(懒加载与贪婪的区别在于懒加载在每次读取后都会释放线程)。

它仍然没有达到应有的速度,主要因为使用了fetch_update而不是CPU内嵌函数。如果有人有改进此处的想法,请在rust discord上联系我(ID为@Zyansheep#8020)。

依赖项

~0–26MB
~334K SLoC