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

标签 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();
}

最佳答案

有很多方法可以在线程之间发送数据——没有一个明确的“最佳”解决方案。这取决于你的情况。

仅使用 thread::join
很多人没有意识到,您只需使用 thread 就可以非常轻松地发送数据。 API,但只有两次:一次到新线程,一次返回。

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!

( Playground )

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

来自 std 的 channel

标准库提供了 multi producer single consumer channel in std::sync::mpsc .您可以通过一个 channel 发送任意多个值,因此可以在更多情况下使用。简单的例子:

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();

( Playground )

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

更强大的 channel 来自 crossbeam
不幸的是,标准库目前仅提供仅限于单个使用者的 channel (即 Receiver 无法克隆)。要获得更强大的 channel ,您可能需要使用 channels from the awesome crossbeam library .他们的描述:

This crate is an alternative to std::sync::mpsc with more features and better performance.



特别是,它是一个 mpmc(多消费者!) channel 。这提供了一种在多个线程之间轻松共享工作的好方法。例子:

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 :(");
}

( Playground )

同样,添加另一个 channel 允许您将结果传送回主线程。

其他方法

还有很多其他的 crate 提供了在线程之间发送数据的其他方法。太多了,无法在此一一列出。

请注意,发送数据并不是线程间通信的唯一方式。还可以通过 Mutex 在线程之间共享数据, atomics 、无锁数据结构等多种方式。这在概念上是非常不同的。这取决于具体情况,发送或共享数据是描述跨线程通信的更好方式。

关于multithreading - 在线程之间发送数据的惯用方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59075477/

相关文章:

c++ - 为什么互斥锁被解锁

java - 如何在 Java 中暂停和恢复简单的游戏

c - 随机矩形上的 Windows API 程序...我不知道变量如何获取其值

c# - 多线程并行阶乘

stack - 使用内联汇编更改堆栈指针时调用函数会崩溃

rust - cargo 生成在 Ubuntu 20.04 上安装失败

postgresql - 如何防止BB8连接在多次重复后断开

java - 这个示例代码是简单的还是有理由在这里使用 interrupt()

rust - 如何使 rustc-link-search 相对于项目位置?

rust - 我什么时候应该在 Rust 中使用特征作为类型?