src/concurrency/async-control-flow/channels.md
Several crates have support for asynchronous channels. For instance tokio:
# // Copyright 2024 Google LLC
# // SPDX-License-Identifier: Apache-2.0
#
use tokio::sync::mpsc;
async fn ping_handler(mut input: mpsc::Receiver<()>) {
let mut count: usize = 0;
while let Some(_) = input.recv().await {
count += 1;
println!("Received {count} pings so far.");
}
println!("ping_handler complete");
}
#[tokio::main]
async fn main() {
let (sender, receiver) = mpsc::channel(32);
let ping_handler_task = tokio::spawn(ping_handler(receiver));
for i in 0..10 {
sender.send(()).await.expect("Failed to send ping.");
println!("Sent {} pings so far.", i + 1);
}
drop(sender);
ping_handler_task.await.expect("Something went wrong in ping handler task.");
}
Change the channel size to 3 and see how it affects the execution.
Overall, the interface is similar to the sync channels as seen in the
morning class.
Try removing the std::mem::drop call. What happens? Why?
The Flume crate has channels that
implement both sync and async send and recv. This can be convenient
for complex applications with both IO and heavy CPU processing tasks.
What makes working with async channels preferable is the ability to combine
them with other futures to combine them and create complex control flow.