如何优化 Rust 中共享 Vec 中独立元素的并发访问?

问题描述 投票:0回答:1

简介

我正在开发一个并发 Rust 应用程序,我需要多个线程来访问和修改共享数据结构的不同部分。据我所知,Rust 强制执行严格的借用规则来防止数据竞争,这会使并发上下文中的多个可变引用变得复杂。但是,我想优化我的设计以最小化锁定开销并最大化并发性。

假设我有一个存储多个项目的 Vec,并且我希望每个线程处理向量中的不同元素,而不会阻塞其他线程。我考虑过使用 MutexRwLock,但这些会增加 global 锁定开销,出于性能原因,我希望避免这种情况。我正在寻找更精细的并发控制,允许线程独立修改不同的元素。

代码示例

这是我当前设置的简化版本:

use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    let data = Arc::new(Mutex::new(vec![1, 2, 3, 4]));

    let mut handles = vec![];
    for i in 0..4 {
        let data = Arc::clone(&data);
        let handle = thread::spawn(move || {
            let mut data = data.lock().unwrap();
            data[i] += 1;
        });
        handles.push(handle);
    }

    for handle in handles {
        handle.join().unwrap();
    }
    println!("{:?}", *data.lock().unwrap());
}

这段代码可以工作,但是在整个 Vec 周围使用互斥锁意味着一次只有一个线程可以修改任何元素,这可能会导致性能瓶颈。

问题

  • 在并发 Rust 代码中处理多个可变引用的有效方法是什么,以便线程可以独立修改数据结构的不同部分?

P.S. 我读过有关使用 Atomic 类型、Crossbeam 甚至将结构拆分为独立块等选项,但我不确定在 Rust 中优化并发访问的最佳方法是什么。

P.P.S. 由于我对这门语言本身相当陌生,我的一些前提甚至可能不正确,所以请持保留态度。

multithreading rust concurrency mutex mutable-reference
1个回答
0
投票

split_at_mut
切片方法在这里派上用场。使用它,您可以将任何取消引用切片的内容(数组、
Vec
等)划分为不相交的段,这两个段都可以同时发生变化。

为此,您不能使用

Arc
与线程共享数据;您需要直接共享参考。为了让 that 工作,您需要使用 作用域线程

这是一个与您的代码执行相同操作的示例,但不需要锁定或

Arc

use std::thread;

fn main() {
    let mut data = vec![1, 2, 3, 4];

    let mut remaining_data = &mut data[..];

    thread::scope(|s| {
        while !remaining_data.is_empty() {
            // Split off the first element into its own slice.
            let thread_data;
            (thread_data, remaining_data) = remaining_data.split_at_mut(1);

            // Take a reference to the only element to keep the thread code
            // simpler.
            let thread_data = &mut thread_data[0];

            s.spawn(|| {
                *thread_data += 1;
            });
        }
    });

    assert_eq!(&[2, 3, 4, 5], &data[..]);
}
© www.soinside.com 2019 - 2024. All rights reserved.