Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.9k views
in Technique[技术] by (71.8m points)

multithreading - What are idiomatic ways to send data between threads?

I want to do some calculation in a separate thread, and then recover the data from the main thread. What are the canonical ways to pass some data from a thread to another in 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();
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

There are lots of ways to send send data between threads -- without a clear "best" solution. It depends on your situation.


Using just thread::join

Many people do not realize that you can very easily send data with only the thread API, but only twice: once to the new thread and once back.

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)

This is immensely useful for threads that are just spawned to do one specific job. Note the move keyword before the closure that makes sure all referenced variables are moved into the closure (which is then moved to another thread).


Channels from std

The standard library offers a multi producer single consumer channel in std::sync::mpsc. You can send arbitrarily many values through a channel, so it can be used in more situations. Simple example:

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)

Of course you can create another channel to provide communication in the other direction as well.


More powerful channels by crossbeam

Unfortunately, the standard library currently only provides channels that are restricted to a single consumer (i.e. Receiver can't be cloned). To get more powerful channels, you probably want to use the channels from the awesome crossbeam library. Their description:

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

In particular, it is a mpmc (multi consumer!) channel. This provides a nice way to easily share work between multiple threads. Example:

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)

Again, adding another channel allows you to communicate results back to the main thread.


Other methods

There are plenty of other crates that offer some other means of sending data between threads. Too many to list them here.

Note that sending data is not the only way to communicate between threads. There is also the possibility to share data between threads via Mutex, atomics, lock-free data structures and many other ways. This is conceptually very different. It depends on the situation whether sending or sharing data is the better way to describe your cross thread communication.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...