在线程之间发送数据的惯用方式是什么?

Fre*_*ios 4 multithreading rust

我想在一个单独的线程中进行一些计算,然后从主线程中恢复数据。在Rust中将一些数据从线程传递到另一个的规范方法是什么?

fn main() {
    let handle = std::thread::spawn(|| {
        // I want to send this to the main thread:
        String::from("Hello world!")
    });

    // How to recover the data from the other thread?

    handle.join().unwrap();
}
Run Code Online (Sandbox Code Playgroud)

Luk*_*odt 6

在线程之间有许多发送发送数据的方法-没有明确的“最佳”解决方案。这取决于您的情况。


仅使用 thread::join

许多人没有意识到您可以非常轻松地仅使用threadAPI 发送数据,但是只能发送两次:一次发送到新线程,一次返回。

use std::thread;

let data_in = String::from("lots of data");
let handle = thread::spawn(move || {
    println!("{}", data_in);  // we can use the data here!

    let data_out = heavy_compuations();
    data_out // <-- simply return the data from the closure
});

let data_out = handle.join().expect("thread panicked :(");
println!("{}", data_out);  // we can use the data generated in the thread here!
Run Code Online (Sandbox Code Playgroud)

游乐场

这对于刚产生来完成一项特定工作的线程非常有用。注意move闭包之前的关键字,该关键字确保所有引用的变量都移入闭包(然后移至另一个线程)。


来自的频道 std

标准库提供一个 ULTI p roducer 小号英格尔Ç onsumer在信道std::sync::mpsc。您可以通过通道任意发送许多值,因此可以在更多情况下使用它。简单的例子:

use std::{
    sync::mpsc::channel,
    thread,
    time::Duration,
};

let (sender, receiver) = channel();
thread::spawn(move || {
    sender.send("heavy computation 1").expect("receiver hung up :(");
    thread::sleep(Duration::from_millis(500));
    sender.send("heavy computation 2").expect("receiver hung up :(");
});

let result1 = receiver.recv().unwrap();
let result2 = receiver.recv().unwrap();
Run Code Online (Sandbox Code Playgroud)

游乐场

当然,您可以创建另一个通道来提供另一个方向的通信。


更强大的渠道 crossbeam

不幸的是,标准库目前仅提供仅限于单个使用者的通道(即Receiver无法克隆)。为了获得更强大的渠道,您可能想要使用很棒的crossbeam库中渠道。他们的描述:

此板条箱是std::sync::mpsc具有更多功能和更好性能的替代产品。

特别是,它是一个mpmc(多用户!)通道。这提供了一种轻松地在多个线程之间共享工作的好方法。例:

use std::thread;

// You might want to use a bounded channel instead...
let (sender, receiver) = crossbeam_channel::unbounded();
for _ in 0..num_cpus::get() {
    let receiver = receiver.clone();  // clone for this thread
    thread::spawn(move || {
        for job in receiver {
            // process job
        }
    });
}

// Generate jobs
for x in 0..10_000 {
    sender.send(x).expect("all threads hung up :(");
}
Run Code Online (Sandbox Code Playgroud)

游乐场

同样,添加另一个通道使您可以将结果传递回主线程。


其他方法

还有许多其他的板条箱提供了在线程之间发送数据的其他方法。太多,无法在此处列出。

请注意,发送数据不是线程之间进行通信的唯一方法。还有可能通过,原子,无锁数据结构和许多其他方式在线程之间共享数据。这在概念上是非常不同的。发送或共享数据是描述跨线程通信的更好方法取决于情况。Mutex