Rust 中大量线程的性能下降

Performance degradation for high numbers of threads in Rust

我正在用 Rust 创建无闩锁并发 HashMap。吞吐量曲线看起来与我预期的一样,最多约 16 个线程,此时性能下降。

吞吐量(MOps/sec)与线程数

我使用了具有 48 个 vCPU 和 200GB RAM 的 Google 云实例。我尝试了 enabling/disabling 超线程,但没有明显的结果。

下面是我生成线程的方式:

for i in 0..num_threads {
    //clone the shared data structure
    let ht = Arc::clone(&ht);

    let handle = thread::spawn(move || {
        for j in 0..adds_per_thread {
            //randomly generate and add a (key, value)
            let key = thread_rng().gen::<u32>();
            let value = thread_rng().gen::<u32>();
            ht.set_item(key, value);
        }
    });

    handles.push(handle);
}

for handle in handles {
    handle.join().unwrap();
}

我没主意了;我的 Rust 代码适合多线程吗?

如果您的所有线程都将所有时间都花在您的无锁数据结构上,那么是的,一旦您拥有足够多的线程,就会发生争用。有了足够多的作者,他们会更频繁地争夺 table 中的同一缓存行。 (此外,花在 PRNG 上的时间可能不会隐藏对缓存或 DRAM 的共享带宽的争用)。

您可能会开始遇到更多的 CAS 重试和类似问题,包括任何争用退避机制,而不仅仅是停滞不前。此外,线程将遭受缓存未命中,甚至 来自某些原子读取;并非所有内容都是原子 RMW 或写入。

这不是无锁数据结构的正常用例;通常,您将它们与执行重要工作的代码一起使用,而不是敲打它们,因此实际竞争很低。此外,哈希图的实际工作负载很少是只写的(尽管如果您只想删除某些内容,则可能会发生这种情况)。

读取与读者数量的关系非常好,但写入会引起争用。