Module 9 • Lesson 49

Tokio: Async Runtime

📚 11 min💻 Free🦀 nixus.pro

Tokio: The Async Runtime

use tokio::{
    fs,
    io::{AsyncReadExt, AsyncWriteExt},
    net::{TcpListener, TcpStream},
    sync::{mpsc, Mutex, RwLock},
    time::{sleep, timeout, Duration},
};
use std::sync::Arc;

// Async file I/O
async fn read_file(path: &str) -> Result {
    fs::read_to_string(path).await
}

// TCP server
async fn handle_connection(mut stream: TcpStream) {
    let mut buf = [0; 1024];
    match stream.read(&mut buf).await {
        Ok(n) if n > 0 => {
            let msg = String::from_utf8_lossy(&buf[..n]);
            let response = format!("Echo: {}", msg);
            stream.write_all(response.as_bytes()).await.ok();
        }
        _ => {}
    }
}

async fn run_server() {
    let listener = TcpListener::bind("127.0.0.1:8080").await.unwrap();
    println!("Listening on :8080");
    loop {
        let (socket, addr) = listener.accept().await.unwrap();
        println!("Connection from {}", addr);
        tokio::spawn(handle_connection(socket)); // Spawn per connection
    }
}

// Async channels
async fn producer_consumer() {
    let (tx, mut rx) = mpsc::channel::(32);

    tokio::spawn(async move {
        for i in 0..5 {
            tx.send(format!("message {}", i)).await.unwrap();
            sleep(Duration::from_millis(100)).await;
        }
    });

    while let Some(msg) = rx.recv().await {
        println!("Received: {}", msg);
    }
}

#[tokio::main]
async fn main() {
    // Timeout example
    let result = timeout(
        Duration::from_millis(50),
        sleep(Duration::from_millis(100))
    ).await;
    println!("Timed out: {}", result.is_err()); // true
    
    producer_consumer().await;
}

🎯 Practice

  1. Write an async TCP echo server using tokio::net::TcpListener
  2. Use tokio::mpsc to implement a background task that processes work items
  3. Write a function that retries an async operation up to 3 times with exponential backoff

🎉 Key Takeaways