Tokio runtime
- Rust course
- Advanced
- Lesson 7/81
- 4 min
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
use std::future::Future;
use std::pin::pin;
use std::task::{Context, Poll, Waker};
fn main() {
// buraya yaz
}Sample solution
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
#[tokio::____]
async fn main() {
println!("başladı");
}
#[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 |