在 Rust 的线程之间共享只读对象?

Joe*_*Joe 5 rust

我正在尝试开始使用 Rust 线​​程。在我的示例中(人为设计但基于实际问题),我想接受一个只读HashMap作为函数的参数,然后将其提供给多个线程,每个线程都从它的分区中读取。

use std::{
    collections::HashMap,
    sync::{mpsc::channel, Arc},
    thread,
};

const THREADS: u32 = 10;

// Concurrently add the lengths of values.
pub fn concurrent_lens(inputs: &HashMap<u32, String>) -> usize {
    let inputs_arc = Arc::new(inputs);

    let (tx, rx) = channel();

    // Count length of all strings in parallel.
    // Each thread takes a partition of the data.
    for thread_i in 0..THREADS {
        let tx = tx.clone();
        let inputs_clone = inputs_arc.clone();

        thread::spawn(move || {
            for (i, content) in inputs_clone.iter() {
                // Only look at my partition's keys.
                if (i % THREADS) == thread_i {
                    // Something expensive with the string.
                    let expensive_operation_result = content.len();

                    tx.send(expensive_operation_result).unwrap();
                }
            }
        });
    }

    // Join and sum results.
    let mut result = 0;
    for len in rx.iter() {
        result += len;
    }

    result
}
Run Code Online (Sandbox Code Playgroud)

但是,编译器说:

use std::{
    collections::HashMap,
    sync::{mpsc::channel, Arc},
    thread,
};

const THREADS: u32 = 10;

// Concurrently add the lengths of values.
pub fn concurrent_lens(inputs: &HashMap<u32, String>) -> usize {
    let inputs_arc = Arc::new(inputs);

    let (tx, rx) = channel();

    // Count length of all strings in parallel.
    // Each thread takes a partition of the data.
    for thread_i in 0..THREADS {
        let tx = tx.clone();
        let inputs_clone = inputs_arc.clone();

        thread::spawn(move || {
            for (i, content) in inputs_clone.iter() {
                // Only look at my partition's keys.
                if (i % THREADS) == thread_i {
                    // Something expensive with the string.
                    let expensive_operation_result = content.len();

                    tx.send(expensive_operation_result).unwrap();
                }
            }
        });
    }

    // Join and sum results.
    let mut result = 0;
    for len in rx.iter() {
        result += len;
    }

    result
}
Run Code Online (Sandbox Code Playgroud)

我的选择是,据我所知:

  • 使inputs静态。这是不可能的,因为它不是静态数据。
  • 让函数拥有所有权input(而不是引用)。所以我的功能是pub fn concurrent_lens(inputs: HashMap<u32, String>) -> usize. 这让编译器对它的生命周期感到满意,但数据存在于函数之外,并且在外部具有更长的生命周期。
  • 同上,但传递一份副本。不理想,它有很多数据。
  • 让函数以 Arc 作为参数,即pub fn concurrent_lens(inputs: Arc<HashMap<u32, String>>) -> usize。这工作正常,但似乎是一个真正有漏洞的抽象,因为调用代码不应该知道它正在调用一个使用并发的函数。

这些似乎都不对。我错过了什么吗?