Skip to content

Understanding Rust Futures

How do we recv some messages while sending other? How to keep them seperate but have them run simultaneously

A future holds what your going to get out of something. Think of a future as a unit of work that will be executed later but not immeditately. Use the async keyword to define a block of code that returns a future, and thus will execute when you call it in the future. EVerytime we use the await keyword we may be stopped so put this on hold, and come back later.

You have to consume the futures to actually execute them. You can use an executor (e.g. futures::executor::blockon())

To work with futures you have to pull in crates "async_std", "futures", "futures-timer"


Rust implements asynchronous programming with a feature called async/await. You must label asynchronous function with the async keyword. This tells the complier that the function will actually return a future to its specified return type (more accurately, a type that implements the Future trait). You call await on an asynchronous function yields control back to the thread, and the program will only continue operating on the subsequent logic once that future is resolved.

Calling an async function doesn't result in the function body executing, you HAVE to call await in order for it to begin execution. In this way, Rust's async operations are lazy.

[! Note] Asynchronous functions must be executed by a runtime such as Tokio. This includes the task scheduler, I/O, timers, etc.

Consider the following snippet

rust
use tokio::sync::mpsc;

#[tokio::main]
async fn main() {
    let (tx, mut rx) = mpsc::channel(32);
    let tx2 = tx.clone();

    tokio::spawn(async move {
        tx.send("sending from first handle").await;
    });

    tokio::spawn(async move {
        tx2.send("sending from second handle").await;
    });

    while let Some(message) = rx.recv().await {
        println!("GOT = {}", message);
    }
use tokio::sync::mpsc;

#[tokio::main]
async fn main() {
    let (tx, mut rx) = mpsc::channel(32);
    let tx2 = tx.clone();

    tokio::spawn(async move {
        tx.send("sending from first handle").await;
    });

    tokio::spawn(async move {
        tx2.send("sending from second handle").await;
    });

    while let Some(message) = rx.recv().await {
        println!("GOT = {}", message);
    }

The function issues .await on the tx.send calls, however, since these operations are done in a separately spawned task, the don't block the current threads, while ends up awaiting for their eventually completion in a recv loop.