使用旧Rust 2015
0.0.1 |
|
---|
#38 in #spsc
255KB
353 代码行
有界SPSC队列
注意: 此仓库是Polyfractal的bounded-spsc-queue
的硬分叉,因为我注意到它已经有一段时间没有更新了。
此crate为Rust提供了一个非常简单的有界、单生产者单消费者(SPSC)队列。它为两个线程在一个方向上以最小的开销和有界语义进行通信提供了数据结构。
与sync_channel
相比,此队列提供了小幅但一致的加速。在内部,sync_channel
使用无界链表数据结构,而bounded_spsc_queue
是一个简单的环形缓冲区,拥有一个连续的内存块。这个连续的内存块由于减少了指针间接,允许更好的缓存预取,并且通常操作更简单,以实现有界SPSC队列。
文档
示例
use std::thread;
use bounded_spsc_queue::{Producer, Consumer};
// Initialize a queue with capacity of 500 values
let (p, c) = bounded_spsc_queue::make(500);
// Spawn a new thread and move the Producer into it
thread::spawn(move|| {
for i in 0..100000 {
p.push(i);
}
});
// Back in the first thread, start pop'ing values off the queue
for i in 0..100000 {
let t = c.pop();
assert!(t == i);
}
半科学基准测试
在我的Macbook Air(双核1.7 GHz Intel Core i7)上,sync_channel
可以在约200纳秒内执行单线程的send()/recv()
配对操作。
spsc
在约10纳秒内执行相同的测试。
一个更现实的、尽管更难准确基准测试的测试是线程性能。此测试启动一个"监听"线程,该线程尝试尽可能快地清空队列。它必须间歇性地检查一个原子标志以确定测试是否结束,这不幸地会影响基准测试结果。为了减轻这种影响,监听器将只在每500次迭代时检查一次。
在原始线程中,bench测试者尝试将数据推送到队列中。这里的定时可能会出现问题:如果监听器处理速度不够快,生产者在等待队列释放位置时可能会阻塞。这个测试不应被视为延迟测试,而应更多地视为吞吐量测试,因为它实际上是在联合测试生产者和消费者的性能。
sync_channel
在这个测试中得分约为6μs
而spsc
得分约为20ns
另一组基准测试考察了相反的情况(次要线程持续向队列中推送数据,而主线程从队列中取出数据)。定时结果非常相似。
换一种说法
- SPSC每秒执行约50m次推送操作
- 同步通道每秒执行约170k次操作