Есть ли краткий способ порождения новых потоков с копиями существующих данных? - PullRequest
0 голосов
/ 17 мая 2018

Я пытаюсь создать несколько новых потоков, где каждый поток получает собственную копию некоторого состояния. Я хочу вот что:

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 голосов
/ 17 мая 2018

Вы можете использовать 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
}
0 голосов
/ 17 мая 2018

Есть ли лучший способ?

Нет, не используя стандартную библиотеку.Есть прото-RFC о поддержке некоторого синтаксиса для этого, но это далеко не так.У него есть несколько решений, которые вы можете использовать сегодня, например, макрос enclose

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

Это позволяет вам написать свой код следующим образом:

enclose!((data, more_data) {
    thread::spawn(move || foo(data, more_data));
})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...