---
title: tokio Runtime
url: https://doc.liz6.com/en/rust/06-concurrency-and-asynchrony/03-tokio-runtime
locale: en
area: rust
tags:
- rust
- concurrency-and-asynchrony
date: 2026-06-30
modified: 2026-07-16
description: tokio’s reactor (based on epoll/kqueue/IOCP) handles async I/O, and the executor schedules Futures across multiple threads using work-stealing—the combination forms the de facto standard runtime for Rust async. `spawn` submits Futures to a thread pool, `select!` waits on multiple async operations simultaneously—understanding the division of labor between reactor and executor reveals tokio’s performance model.
---

# tokio Runtime

> tokio’s reactor (based on epoll/kqueue/IOCP) handles async I/O, and the executor schedules Futures across multiple threads using work-stealing—the combination forms the de facto standard runtime for Rust async. `spawn` submits Futures to a thread pool, `select!` waits on multiple async operations simultaneously—understanding the division of labor between reactor and executor reveals tokio’s performance model.

## tokio’s Three-Layer Architecture

```mermaid
flowchart TD
    TASK["🧵 Your async task<br/>tokio::spawn"]

    TASK --> QUEUE["📋 Task Queue<br/>Futures waiting to be scheduled"]

    QUEUE --> EXECUTOR["⚙️ Executor<br/>work-stealing scheduler<br/>one worker thread per CPU core"]

    EXECUTOR --> REACTOR["🔌 Reactor<br/>epoll (Linux) / kqueue (macOS)<br/>IOCP (Windows)"]

    REACTOR --> KERNEL["🐧 OS Kernel"]

    REACTOR -.->|"I/O ready → wake task"| QUEUE

    classDef user fill:#e3f2fd,stroke:#1565c0
    classDef middle fill:#fff3e0,stroke:#ef6c00
    classDef os fill:#f3e5f5,stroke:#7b1fa2
    class TASK,QUEUE user
    class EXECUTOR,REACTOR middle
    class KERNEL os
```

**Reactor**: Listens to all registered I/O sources (sockets, timers, signals) → when I/O is ready → notifies the corresponding task to wake up.
**Executor**: Maintains the task queue → woken tasks regain CPU time.
**Your code**: Simply calls `async fn` and uses `.await`, without directly interacting with the reactor or executor.

## Two Types of Runtimes

```rust
// Multi-threaded (default)
#[tokio::main]
async fn main() { ... }

// Equivalent to:
fn main() {
    tokio::runtime::Builder::new_multi_thread()
        .worker_threads(num_cpus::get())  // Default: number of CPU cores
        .enable_all()                     // Enable I/O + time driver
        .build().unwrap()
        .block_on(async { ... });
}

// Single-threaded (for simple scenarios, e.g., no need for cross-thread synchronization)
#[tokio::main(flavor = "current_thread")]
async fn main() { ... }
```

## spawn: Independent Concurrent Tasks

```rust
let handle = tokio::spawn(async move {
    let result = do_heavy_work().await;
    println!("{}", result);
});
// handle: JoinHandle — you can .await it to get the return value
let result = handle.await.unwrap();
```

Tasks spawned via `spawn` can execute on different worker threads—they are truly concurrent, not just coroutines. The returned `JoinHandle` is itself a Future; `.await`ing it waits for the task to complete.

## Work-Stealing Scheduler

Each worker thread has its own local task queue. When a worker becomes idle, it randomly steals tasks from other workers. This model is more efficient than “one global queue + all workers competing”—it reduces lock contention because local push/pop operations are lock-free.

## select!: Waiting on Multiple Futures

```rust
tokio::select! {
    result = long_running_op() => { /* handle result */ }
    _ = tokio::signal::ctrl_c() => { /* Ctrl+C signal */ }
}
```

Once any branch completes → the other branches are **cancelled** (dropped). This is async Rust’s built-in cancellation model—no explicit cancellation token is needed. The `Drop` implementation of the cancelled Future is responsible for cleaning up resources.

## References

- **tokio**: docs.rs/tokio, tokio.rs
- **async book**: rust-lang.github.io/async-book

*Keywords: tokio, reactor, executor, work stealing, spawn, select!, runtime, current_thread*
