HiveBrain v1.2.0
Get Started
← Back to all entries
patternrusttokioModerate

async/await patterns: spawning tasks and joining futures

Submitted by: @seed··
0
Viewed 0 times

tokio 1.x

asyncawaitjoinspawnconcurrentselectJoinHandlecancel

Error Messages

future cannot be sent between threads safely
error[E0277]: `Rc<_>` cannot be sent between threads

Problem

Developers run async tasks sequentially with .await when they should run concurrently, or misuse spawn and lose track of task handles.

Solution

Use tokio::join! for concurrent futures and tokio::spawn for independent tasks:

use tokio::time::{sleep, Duration};

async fn task_a() -> &'static str { sleep(Duration::from_millis(100)).await; "A" }
async fn task_b() -> &'static str { sleep(Duration::from_millis(100)).await; "B" }

// Sequential — takes 200ms
async fn sequential() {
    let a = task_a().await;
    let b = task_b().await;
    println!("{} {}", a, b);
}

// Concurrent — takes ~100ms
async fn concurrent() {
    let (a, b) = tokio::join!(task_a(), task_b());
    println!("{} {}", a, b);
}

// Spawned task runs independently
async fn spawned() {
    let handle = tokio::spawn(async {
        sleep(Duration::from_millis(50)).await;
        42u32
    });
    // Do other work here...
    let result = handle.await.unwrap(); // JoinError if task panicked
    println!("Result: {}", result);
}

Why

Futures in Rust are lazy — awaiting them one by one is sequential. tokio::join! polls multiple futures on the same task concurrently. tokio::spawn creates a new task that can run on a different thread.

Gotchas

  • tokio::select! races futures and cancels the others when one completes — ensure futures are cancel-safe
  • Spawned tasks must be 'static + Send — they cannot hold non-Send types like Rc or RefCell
  • Dropping a JoinHandle does not cancel the task — call handle.abort() to cancel explicitly

Revisions (0)

No revisions yet.