49·异步编程进阶

Tokio 运行时

Tokio 运行时

学习目标

  1. 理解 Tokio 运行时
  2. 掌握常用 API
  3. 理解多线程 vs 当前线程运行时

核心概念

基本用法

#[tokio::main]
async fn main() {
    println!("Hello from Tokio!");
}

// 等价于
fn main() {
    tokio::runtime::Runtime::new()
        .unwrap()
        .block_on(async {
            println!("Hello from Tokio!");
        })
}

常用 API

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

#[tokio::main]
async fn main() {
    // spawn 并发任务
    let handle = tokio::spawn(async {
        sleep(Duration::from_secs(1)).await;
        "done"
    });

    // 超时
    match timeout(Duration::from_millis(500), handle).await {
        Ok(result) => println!("完成: {:?}", result),
        Err(_) => println!("超时"),
    }

    // select!
    tokio::select! {
        _ = sleep(Duration::from_secs(1)) => println!("sleep 完成"),
        _ = sleep(Duration::from_secs(2)) => println!("这个不会执行"),
    }
}

运行时配置

#[tokio::main(flavor = "current_thread")]  // 单线程运行时
async fn main() {
    // 适合 IO 密集型
}

#[tokio::main(flavor = "multi_thread", worker_threads = 4)]
async fn main() {
    // 4 个工作线程
}

IO 操作

use tokio::fs;
use tokio::io::{AsyncReadExt, AsyncWriteExt};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 异步读文件
    let content = fs::read_to_string("data.txt").await?;
    println!("{}", content);

    // 异步写文件
    fs::write("output.txt", "hello").await?;

    // TCP
    let listener = tokio::net::TcpListener::bind("127.0.0.1:8080").await?;
    loop {
        let (socket, addr) = listener.accept().await?;
        tokio::spawn(async move {
            // 处理连接
        });
    }
}

实践练习

练习 1:并发 URL 抓取

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

async fn fetch_url(url: &str) -> String {
    sleep(Duration::from_millis(100)).await;
    format!("Response from {}", url)
}

#[tokio::main]
async fn main() {
    let urls = vec!["http://a.com", "http://b.com", "http://c.com"];
    let mut handles = vec![];

    for url in urls {
        handles.push(tokio::spawn(fetch_url(url).to_string()));
    }

    for handle in handles {
        println!("{}", handle.await.unwrap());
    }
}

小结

API用途
#[tokio::main]异步 main
tokio::spawn并发任务
tokio::select!选择最快完成的
tokio::time::sleep异步休眠
tokio::fs异步文件操作
tokio::net异步网络

练习编辑器

rust
Loading...