Sharing data through channels
An alternative approach to sharing data between threads, is to pass messages between threads using so-called: channels. By employing channels, each thread owns its own data, and the messages are synchronized in a thread-safe manner. Let's re-write our example using channels.
use tokio::join; use tokio::spawn; use tokio::sync::mpsc; #[derive(Debug)] struct User { id: String, } async fn lookup_user(id: &str, mut user_chan: mpsc::Sender<User>) { user_chan .send(User { id: id.to_string() }) .await .expect("can not send user on channel"); } #[tokio::main] async fn main() { let (tx, mut rx) = mpsc::channel(100); let mut users = vec![]; spawn(async move { join! { lookup_user("bob", tx.clone()), lookup_user("tom", tx), } }); while let Some(user) = rx.recv().await { println!("received: {user:?}"); users.push(user); } println!("Users: {users:?}"); }
As you can see, the users
list does not need to be wrapped in a Mutex
. This is because the main
thread is the
only thread that is manipulating the users
Vec. The lookup_user()
function is returning the User
through the
Sender
half of the mpsc::channel
. The data on the channel is automatically synchronized between threads.
mpsc stands for 'multi-producer, single-consumer' and supports sending many values from many producers to a single consumer. See Module tokio::sync for other channel types.
The channel constructor returns a tuple: tx
and rx
. These represent the Sender
and Receiver
halves of the
channel.
Only the Sender
half can be cloned, hence the multi-producer
term.
Notice that we are using the
join!
macro from thetokio
crate toawait
bothlookup_user
tasks.
If at all possible, prefer channels above sharing data between threads. It saves you from performance bottlenecks, where
threads are waiting on a Mutex
lock. Channels, like the above, are buffered such that (up to a certain point) threads
can continue to send data without a delay.
Exercises
Now that you've learned about asynchronous programming with tokio
, it's time to put your knowledge to the test.
Check out the corresponding exercise in the Exercises section. See you next time!