是否有一种简洁的方法来生成包含现有数据副本的新线程?

时间:2018-05-17 14:21:44

标签: rust

我试图产生几个新线程,每个线程都有自己的某个状态的副本。我想要的是这个:

use std::thread;

fn main() {
    let data = vec![42; 10];
    let more_data = "Important data".to_string();
    for _ in 1..=4 {
        thread::spawn(|| foo(data.clone(), more_data.clone()));
    }
}

fn foo(_data: Vec<u64>, _more_data: String) {}

这不能编译,因为克隆是在新线程上完成的,这可能比主线程更长。很公平,但似乎没有好的方法告诉Rust在主线程上执行克隆,然后然后将所有权移动到新线程。每当我遇到这个问题时,我最终会这样做:

use std::thread;

fn main() {
    let data = vec![42; 10];
    let more_data = "Important data".to_string();
    for _ in 1..=4 {
        let cloned_data = data.clone();
        let cloned_more_data = more_data.clone();
        thread::spawn(move || foo(cloned_data, cloned_more_data));
    }
}

fn foo(_data: Vec<u64>, _more_data: String) {}

它做了我想要的,但它非常嘈杂和样板,特别是有很多争论。还有更好的方法吗?

2 个答案:

答案 0 :(得分:2)

  

有更好的方法吗?

不,不使用标准库。这有a proto-RFC about supporting some syntax,但这远远没有发生。它确实有多种解决方案供您今天使用,例如enclose macro

macro_rules! enclose {
    ( ($( $x:ident ),*) $y:expr ) => {
        {
            $(let $x = $x.clone();)*
            $y
        }
    };
}

这允许您编写如下代码:

enclose!((data, more_data) {
    thread::spawn(move || foo(data, more_data));
})

答案 1 :(得分:2)

您可以使用iter::repeat()为您克隆数据:

use std::thread;

fn main() {
    let data = vec![42; 10];
    let more_data = "Important data".to_string();
    let threads: Vec<_> = std::iter::repeat((data, more_data))
        .take(5)
        .map(|(data, more_data)| thread::spawn(|| foo(data, more_data)))
        .collect();
    let result: Vec<_> = threads.into_iter().map(|x| x.join()).collect();
    result.iter().for_each(|x| {
        println!("{:?}", x);
    });
}

fn foo(_data: Vec<u64>, _more_data: String) -> u64 {
    println!("Hello");
    42
}