CodeBlanks Logo Icon CodeBlanks

Tokio runtime

Start a runtime with #[tokio::main].

The Tokio runtime

tokio is Rust's most common asynchronous runtime: it offers a thread pool, task scheduler, timers and async network/file APIs. The #[tokio::main] attribute makes main async:

// Cargo.toml: tokio = { version = "1", features = ["full"] }
#[tokio::main]
async fn main() {
    let veri = indir("https://..").await;
}

// roughly expands to:
fn main() {
    tokio::runtime::Runtime::new().unwrap().block_on(async {
        let veri = indir("https://..").await;
    })
}

So the macro calls a much more advanced version of the block_on we wrote in the previous group.

Runtime flavours

Tokio offers two schedulers: multi-threaded (the default, tasks spread across CPU cores) and single-threaded (current_thread, for tests and small tools):

#[tokio::main(flavor = "current_thread")]
async fn main() { .. }

#[tokio::test]
async fn async_test() {
    assert_eq!(hesapla().await, 42);
}

#[tokio::test] sets up a separate runtime for each test.

Practice What the macro expands to

Imitate the expansion of #[tokio::main]: write the block_on executor, and let async fn baslat() -> &'static str return "sunucu başladı". In main, print the result of block_on(async { baslat().await }).

Starter code

main.rs
use std::future::Future;
use std::pin::pin;
use std::task::{Context, Poll, Waker};

fn main() {
    // buraya yaz
}

Sample solution

main.rs
use std::future::Future;
use std::pin::pin;
use std::task::{Context, Poll, Waker};

fn block_on<F: Future>(f: F) -> F::Output {
    let mut f = pin!(f);
    let mut cx = Context::from_waker(Waker::noop());
    loop {
        if let Poll::Ready(v) = f.as_mut().poll(&mut cx) {
            return v;
        }
    }
}

async fn baslat() -> &'static str {
    "sunucu başladı"
}

fn main() {
    let mesaj = block_on(async { baslat().await });
    println!("{}", mesaj);
}

Expected output

sunucu başladı

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 Why is calling <code>std::thread::sleep</code> in an async task a problem?

  • There's no problem
  • It blocks the runtime's thread; other tasks on the same thread wait too Correct answer
  • It doesn't compile
  • It sleeps longer

Explanation: In async code use tokio::time::sleep(..).await; for blocking work there is tokio::task::spawn_blocking.

2 Runtime entry

Question
#[tokio::____]
async fn main() {
    println!("başladı");
}
Answer
#[tokio::main]
async fn main() {
    println!("başladı");
}

Explanation: #[tokio::main] runs an async main inside a runtime.

3 Tool and role

Term Meaning
#[tokio::main] Async main
#[tokio::test] Async test
current_thread Single thread
spawn_blocking Blocking work

All lessons in Advanced