第九篇: Rust Tokio 完全指南

71 阅读15分钟

Tokio 完全指南

Tokio 是 Rust 最流行的异步运行时(async runtime),为构建高性能、可靠的网络应用提供基础设施。

目录


核心概念

Tokio 是什么?

Tokio 是一个异步运行时,提供:

  1. 任务调度器 - 执行异步任务
  2. I/O 事件循环 - 处理网络/文件 I/O
  3. 定时器 - 延迟和超时
  4. 同步原语 - Mutex、RwLock、Semaphore 等
  5. 通道 - 任务间通信

为什么需要 Tokio?

// ❌ 没有 Tokio:无法运行异步代码
async fn hello() {
    println!("Hello");
}

fn main() {
    hello();  // 这只是创建 Future,不会执行
}

// ✅ 使用 Tokio:执行异步代码
#[tokio::main]
async fn main() {
    hello().await;  // 实际执行
}

Tokio vs 其他运行时

运行时特点适用场景
tokio功能完整、高性能、多线程网络服务、通用应用
async-std类似标准库 API简单应用
smol轻量级嵌入式、小型应用

入门使用

安装

[dependencies]
tokio = { version = "1", features = ["full"] }

常用 Features

[dependencies]
tokio = { version = "1", features = [
    "rt-multi-thread",  # 多线程运行时
    "macros",           # #[tokio::main] 等宏
    "net",              # TCP/UDP 网络
    "io-util",          # AsyncReadExt 等工具
    "time",             # 定时器
    "sync",             # 同步原语
    "fs",               # 异步文件 I/O
    "process",          # 异步进程
    "signal",           # 信号处理
] }

# 或简单使用所有功能
tokio = { version = "1", features = ["full"] }

Hello World

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

#[tokio::main]
async fn main() {
    println!("Hello");
    sleep(Duration::from_secs(1)).await;
    println!("World");
}

异步运行时

#[tokio::main] 宏

// 方式1:使用宏(推荐)
#[tokio::main]
async fn main() {
    println!("Hello Tokio");
}

// 宏展开后相当于:
fn main() {
    tokio::runtime::Builder::new_multi_thread()
        .enable_all()
        .build()
        .unwrap()
        .block_on(async {
            println!("Hello Tokio");
        })
}

自定义运行时

多线程运行时
use tokio::runtime::Runtime;

fn main() {
    let rt = Runtime::new().unwrap();
    
    rt.block_on(async {
        println!("Running on multi-thread runtime");
    });
}

// 自定义配置
fn main() {
    let rt = tokio::runtime::Builder::new_multi_thread()
        .worker_threads(4)           // 4 个工作线程
        .thread_name("my-pool")      // 线程名称
        .thread_stack_size(3 * 1024 * 1024)  // 栈大小
        .enable_all()                // 启用所有功能
        .build()
        .unwrap();
    
    rt.block_on(async {
        println!("Custom runtime");
    });
}
单线程运行时
fn main() {
    let rt = tokio::runtime::Builder::new_current_thread()
        .enable_all()
        .build()
        .unwrap();
    
    rt.block_on(async {
        println!("Running on single-thread runtime");
    });
}

Runtime Handle

use tokio::runtime::Handle;

#[tokio::main]
async fn main() {
    // 获取当前运行时句柄
    let handle = Handle::current();
    
    // 在另一个线程中使用运行时
    std::thread::spawn(move || {
        handle.block_on(async {
            println!("Running async code in sync thread");
        });
    });
}

spawn_blocking - 运行阻塞代码

use tokio::task;

#[tokio::main]
async fn main() {
    // CPU 密集型任务
    let result = task::spawn_blocking(|| {
        // 这会在单独的线程池中运行
        expensive_computation()
    })
    .await
    .unwrap();
    
    println!("Result: {}", result);
}

fn expensive_computation() -> u64 {
    (0..1_000_000).sum()
}

任务管理

tokio::spawn - 创建新任务

use tokio::task;

#[tokio::main]
async fn main() {
    // 启动新任务(不等待)
    let handle = tokio::spawn(async {
        println!("Task 1");
        42
    });
    
    // 继续执行其他工作
    println!("Main task");
    
    // 等待任务完成
    let result = handle.await.unwrap();
    println!("Task result: {}", result);
}

并发执行多个任务

#[tokio::main]
async fn main() {
    let task1 = tokio::spawn(async {
        tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
        println!("Task 1 done");
        1
    });
    
    let task2 = tokio::spawn(async {
        tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;
        println!("Task 2 done");
        2
    });
    
    let task3 = tokio::spawn(async {
        tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
        println!("Task 3 done");
        3
    });
    
    // 等待所有任务完成
    let (r1, r2, r3) = tokio::join!(task1, task2, task3);
    
    println!("Results: {:?}, {:?}, {:?}", r1, r2, r3);
}

JoinSet - 动态任务集合

use tokio::task::JoinSet;

#[tokio::main]
async fn main() {
    let mut set = JoinSet::new();
    
    // 动态添加任务
    for i in 0..10 {
        set.spawn(async move {
            tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
            i * 2
        });
    }
    
    // 收集所有结果
    while let Some(res) = set.join_next().await {
        match res {
            Ok(value) => println!("Task completed: {}", value),
            Err(e) => eprintln!("Task failed: {}", e),
        }
    }
}

任务取消

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

#[tokio::main]
async fn main() {
    let handle = tokio::spawn(async {
        loop {
            println!("Working...");
            sleep(Duration::from_secs(1)).await;
        }
    });
    
    // 运行 3 秒后取消
    sleep(Duration::from_secs(3)).await;
    handle.abort();
    
    // 检查是否被取消
    match handle.await {
        Ok(_) => println!("Task completed"),
        Err(e) if e.is_cancelled() => println!("Task was cancelled"),
        Err(e) => println!("Task failed: {}", e),
    }
}

LocalSet - 非 Send 任务

use tokio::task::LocalSet;
use std::rc::Rc;

#[tokio::main]
async fn main() {
    let local = LocalSet::new();
    
    // Rc 不是 Send,不能用普通 spawn
    let data = Rc::new(42);
    
    local.spawn_local(async move {
        println!("Data: {}", data);
    });
    
    local.await;
}

异步 I/O

TCP 服务器

use tokio::net::TcpListener;
use tokio::io::{AsyncReadExt, AsyncWriteExt};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let listener = TcpListener::bind("127.0.0.1:8080").await?;
    println!("服务器启动于 127.0.0.1:8080");
    
    loop {
        let (mut socket, addr) = listener.accept().await?;
        println!("新连接: {}", addr);
        
        // 为每个连接创建新任务
        tokio::spawn(async move {
            let mut buf = vec![0; 1024];
            
            loop {
                match socket.read(&mut buf).await {
                    Ok(0) => return,  // 连接关闭
                    Ok(n) => {
                        // 回显数据
                        if socket.write_all(&buf[0..n]).await.is_err() {
                            return;
                        }
                    }
                    Err(_) => return,
                }
            }
        });
    }
}

TCP 客户端

use tokio::net::TcpStream;
use tokio::io::{AsyncReadExt, AsyncWriteExt};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut stream = TcpStream::connect("127.0.0.1:8080").await?;
    println!("已连接到服务器");
    
    // 发送数据
    stream.write_all(b"Hello, Server!").await?;
    
    // 读取响应
    let mut buf = vec![0; 1024];
    let n = stream.read(&mut buf).await?;
    
    println!("收到响应: {}", String::from_utf8_lossy(&buf[0..n]));
    
    Ok(())
}

UDP

use tokio::net::UdpSocket;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let socket = UdpSocket::bind("127.0.0.1:8080").await?;
    let mut buf = [0; 1024];
    
    loop {
        let (len, addr) = socket.recv_from(&mut buf).await?;
        println!("收到 {} 字节,来自 {}", len, addr);
        
        // 回显
        socket.send_to(&buf[0..len], addr).await?;
    }
}

异步文件操作

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

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 写文件
    let mut file = File::create("hello.txt").await?;
    file.write_all(b"Hello, Tokio!").await?;
    
    // 读文件
    let mut file = File::open("hello.txt").await?;
    let mut contents = String::new();
    file.read_to_string(&mut contents).await?;
    println!("文件内容: {}", contents);
    
    // 追加写入
    let mut file = OpenOptions::new()
        .append(true)
        .open("hello.txt")
        .await?;
    file.write_all(b"\nNew line").await?;
    
    // 读取整个文件
    let contents = tokio::fs::read_to_string("hello.txt").await?;
    println!("{}", contents);
    
    Ok(())
}

异步进程

use tokio::process::Command;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let output = Command::new("echo")
        .arg("Hello from Tokio")
        .output()
        .await?;
    
    println!("Status: {}", output.status);
    println!("Stdout: {}", String::from_utf8_lossy(&output.stdout));
    
    Ok(())
}

同步原语

Mutex - 互斥锁

use tokio::sync::Mutex;
use std::sync::Arc;

#[tokio::main]
async fn main() {
    let counter = Arc::new(Mutex::new(0));
    let mut handles = vec![];
    
    for _ in 0..10 {
        let counter = Arc::clone(&counter);
        let handle = tokio::spawn(async move {
            let mut num = counter.lock().await;
            *num += 1;
        });
        handles.push(handle);
    }
    
    for handle in handles {
        handle.await.unwrap();
    }
    
    println!("Result: {}", *counter.lock().await);
}

RwLock - 读写锁

use tokio::sync::RwLock;
use std::sync::Arc;

#[tokio::main]
async fn main() {
    let data = Arc::new(RwLock::new(vec![1, 2, 3]));
    
    // 多个读者
    let data1 = Arc::clone(&data);
    tokio::spawn(async move {
        let read_guard = data1.read().await;
        println!("Reader 1: {:?}", *read_guard);
    });
    
    let data2 = Arc::clone(&data);
    tokio::spawn(async move {
        let read_guard = data2.read().await;
        println!("Reader 2: {:?}", *read_guard);
    });
    
    // 一个写者
    tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
    let mut write_guard = data.write().await;
    write_guard.push(4);
    println!("Writer: {:?}", *write_guard);
}

Semaphore - 信号量

use tokio::sync::Semaphore;
use std::sync::Arc;

#[tokio::main]
async fn main() {
    // 最多 3 个并发任务
    let semaphore = Arc::new(Semaphore::new(3));
    let mut handles = vec![];
    
    for i in 0..10 {
        let permit = semaphore.clone().acquire_owned().await.unwrap();
        let handle = tokio::spawn(async move {
            println!("Task {} 开始", i);
            tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
            println!("Task {} 完成", i);
            drop(permit);  // 释放许可
        });
        handles.push(handle);
    }
    
    for handle in handles {
        handle.await.unwrap();
    }
}

Barrier - 屏障

use tokio::sync::Barrier;
use std::sync::Arc;

#[tokio::main]
async fn main() {
    let barrier = Arc::new(Barrier::new(3));
    let mut handles = vec![];
    
    for i in 0..3 {
        let b = Arc::clone(&barrier);
        handles.push(tokio::spawn(async move {
            println!("Task {} 到达屏障前", i);
            b.wait().await;
            println!("Task {} 通过屏障", i);
        }));
    }
    
    for handle in handles {
        handle.await.unwrap();
    }
}

Notify - 通知

use tokio::sync::Notify;
use std::sync::Arc;

#[tokio::main]
async fn main() {
    let notify = Arc::new(Notify::new());
    let notify2 = notify.clone();
    
    let handle = tokio::spawn(async move {
        println!("等待通知...");
        notify2.notified().await;
        println!("收到通知!");
    });
    
    tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
    println!("发送通知");
    notify.notify_one();
    
    handle.await.unwrap();
}

定时器

sleep - 延迟

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

#[tokio::main]
async fn main() {
    println!("开始");
    sleep(Duration::from_secs(2)).await;
    println!("2秒后");
}

interval - 定时器

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

#[tokio::main]
async fn main() {
    let mut interval = interval(Duration::from_secs(1));
    
    for i in 0..5 {
        interval.tick().await;
        println!("Tick {}", i);
    }
}

timeout - 超时

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

#[tokio::main]
async fn main() {
    let result = timeout(Duration::from_secs(2), async {
        sleep(Duration::from_secs(3)).await;
        "完成"
    })
    .await;
    
    match result {
        Ok(value) => println!("完成: {}", value),
        Err(_) => println!("超时!"),
    }
}

Instant - 时间点

use tokio::time::Instant;

#[tokio::main]
async fn main() {
    let start = Instant::now();
    
    tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
    
    let elapsed = start.elapsed();
    println!("耗时: {:?}", elapsed);
}

sleep_until - 睡眠到指定时间

use tokio::time::{sleep_until, Instant, Duration};

#[tokio::main]
async fn main() {
    let deadline = Instant::now() + Duration::from_secs(5);
    
    println!("等待到 {:?}", deadline);
    sleep_until(deadline).await;
    println!("时间到!");
}

通道 (Channels)

mpsc - 多生产者单消费者

use tokio::sync::mpsc;

#[tokio::main]
async fn main() {
    let (tx, mut rx) = mpsc::channel(32);  // 缓冲区大小 32
    
    // 发送者
    tokio::spawn(async move {
        for i in 0..10 {
            tx.send(i).await.unwrap();
        }
    });
    
    // 接收者
    while let Some(value) = rx.recv().await {
        println!("收到: {}", value);
    }
}

多个发送者

use tokio::sync::mpsc;

#[tokio::main]
async fn main() {
    let (tx, mut rx) = mpsc::channel(32);
    
    // 多个发送者
    for i in 0..3 {
        let tx = tx.clone();
        tokio::spawn(async move {
            tx.send(format!("Message from sender {}", i)).await.unwrap();
        });
    }
    
    drop(tx);  // 关闭原始发送者
    
    // 接收所有消息
    while let Some(msg) = rx.recv().await {
        println!("{}", msg);
    }
}

unbounded_channel - 无界通道

use tokio::sync::mpsc;

#[tokio::main]
async fn main() {
    let (tx, mut rx) = mpsc::unbounded_channel();
    
    tokio::spawn(async move {
        for i in 0..10 {
            tx.send(i).unwrap();  // 注意:不是异步的
        }
    });
    
    while let Some(value) = rx.recv().await {
        println!("收到: {}", value);
    }
}

oneshot - 一次性通道

use tokio::sync::oneshot;

#[tokio::main]
async fn main() {
    let (tx, rx) = oneshot::channel();
    
    tokio::spawn(async move {
        tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
        tx.send("完成").unwrap();
    });
    
    match rx.await {
        Ok(value) => println!("收到: {}", value),
        Err(_) => println!("发送者已关闭"),
    }
}

broadcast - 广播通道

use tokio::sync::broadcast;

#[tokio::main]
async fn main() {
    let (tx, mut rx1) = broadcast::channel(16);
    let mut rx2 = tx.subscribe();
    let mut rx3 = tx.subscribe();
    
    tokio::spawn(async move {
        for i in 0..5 {
            tx.send(i).unwrap();
        }
    });
    
    let handle1 = tokio::spawn(async move {
        while let Ok(value) = rx1.recv().await {
            println!("Receiver 1: {}", value);
        }
    });
    
    let handle2 = tokio::spawn(async move {
        while let Ok(value) = rx2.recv().await {
            println!("Receiver 2: {}", value);
        }
    });
    
    let handle3 = tokio::spawn(async move {
        while let Ok(value) = rx3.recv().await {
            println!("Receiver 3: {}", value);
        }
    });
    
    handle1.await.unwrap();
    handle2.await.unwrap();
    handle3.await.unwrap();
}

watch - 监视通道

use tokio::sync::watch;

#[tokio::main]
async fn main() {
    let (tx, mut rx) = watch::channel("初始值");
    
    tokio::spawn(async move {
        loop {
            if rx.changed().await.is_ok() {
                println!("值变为: {}", *rx.borrow());
            } else {
                break;
            }
        }
    });
    
    tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
    tx.send("新值1").unwrap();
    
    tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
    tx.send("新值2").unwrap();
    
    tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
}

流 (Streams)

Stream Trait

use tokio_stream::{self as stream, StreamExt};

#[tokio::main]
async fn main() {
    let mut stream = stream::iter(vec![1, 2, 3, 4, 5]);
    
    while let Some(value) = stream.next().await {
        println!("值: {}", value);
    }
}

创建流

use tokio_stream::{StreamExt, wrappers::IntervalStream};
use tokio::time::{interval, Duration};

#[tokio::main]
async fn main() {
    // 从定时器创建流
    let interval = interval(Duration::from_secs(1));
    let mut stream = IntervalStream::new(interval);
    
    for _ in 0..5 {
        stream.next().await;
        println!("Tick");
    }
}

流转换

use tokio_stream::{self as stream, StreamExt};

#[tokio::main]
async fn main() {
    let stream = stream::iter(vec![1, 2, 3, 4, 5]);
    
    // map
    let doubled = stream.map(|x| x * 2);
    
    // filter
    let evens = doubled.filter(|x| x % 2 == 0);
    
    // take
    let mut first_three = evens.take(3);
    
    while let Some(value) = first_three.next().await {
        println!("值: {}", value);
    }
}

流合并

use tokio_stream::{self as stream, StreamExt};

#[tokio::main]
async fn main() {
    let stream1 = stream::iter(vec![1, 2, 3]);
    let stream2 = stream::iter(vec![4, 5, 6]);
    
    // 合并两个流
    let mut merged = stream::iter(vec![stream1, stream2]).flatten();
    
    while let Some(value) = merged.next().await {
        println!("值: {}", value);
    }
}

实用工具

select! - 选择第一个完成的

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

#[tokio::main]
async fn main() {
    let mut count = 0;
    
    loop {
        tokio::select! {
            _ = sleep(Duration::from_secs(1)) => {
                count += 1;
                println!("计数: {}", count);
            }
            _ = sleep(Duration::from_secs(5)), if count >= 3 => {
                println!("5秒过去了");
                break;
            }
        }
    }
}

join! - 等待所有完成

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

#[tokio::main]
async fn main() {
    let task1 = async {
        sleep(Duration::from_secs(1)).await;
        "Task 1"
    };
    
    let task2 = async {
        sleep(Duration::from_secs(2)).await;
        "Task 2"
    };
    
    let task3 = async {
        sleep(Duration::from_secs(1)).await;
        "Task 3"
    };
    
    let (r1, r2, r3) = tokio::join!(task1, task2, task3);
    println!("结果: {}, {}, {}", r1, r2, r3);
}

try_join! - 遇错即停

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

async fn task1() -> Result<&'static str, &'static str> {
    sleep(Duration::from_secs(1)).await;
    Ok("Task 1 成功")
}

async fn task2() -> Result<&'static str, &'static str> {
    sleep(Duration::from_millis(500)).await;
    Err("Task 2 失败")
}

async fn task3() -> Result<&'static str, &'static str> {
    sleep(Duration::from_secs(2)).await;
    Ok("Task 3 成功")
}

#[tokio::main]
async fn main() {
    match tokio::try_join!(task1(), task2(), task3()) {
        Ok((r1, r2, r3)) => println!("{}, {}, {}", r1, r2, r3),
        Err(e) => println!("错误: {}", e),
    }
}

pin! - 固定在栈上

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

#[tokio::main]
async fn main() {
    let task = async {
        sleep(Duration::from_secs(1)).await;
        "完成"
    };
    
    pin!(task);
    
    let result = task.await;
    println!("结果: {}", result);
}

性能优化

1. 选择合适的运行时

// 多线程运行时(默认)- 适合 CPU 密集和 I/O 混合
#[tokio::main]
async fn main() { }

// 单线程运行时 - 适合纯 I/O
#[tokio::main(flavor = "current_thread")]
async fn main() { }

2. 调整工作线程数

fn main() {
    tokio::runtime::Builder::new_multi_thread()
        .worker_threads(num_cpus::get())  // 根据 CPU 核心数
        .build()
        .unwrap()
        .block_on(async {
            // ...
        });
}

3. 使用 spawn_blocking 处理阻塞操作

#[tokio::main]
async fn main() {
    // ❌ 错误:阻塞运行时
    let data = std::fs::read("large_file.txt").unwrap();
    
    // ✅ 正确:在阻塞线程池执行
    let data = tokio::task::spawn_blocking(|| {
        std::fs::read("large_file.txt").unwrap()
    })
    .await
    .unwrap();
}

4. 缓冲和批处理

use tokio::sync::mpsc;

#[tokio::main]
async fn main() {
    let (tx, mut rx) = mpsc::channel(1000);  // 大缓冲区
    
    // 批量处理
    let mut batch = Vec::new();
    while let Some(item) = rx.recv().await {
        batch.push(item);
        
        if batch.len() >= 100 {
            process_batch(&batch).await;
            batch.clear();
        }
    }
}

async fn process_batch(batch: &[i32]) {
    // 批量处理
}

5. 避免过度 spawn

// ❌ 不好:为每个小任务 spawn
for i in 0..1000 {
    tokio::spawn(async move {
        small_work(i).await;
    });
}

// ✅ 更好:批量处理
const CHUNK_SIZE: usize = 100;
for chunk in (0..1000).collect::<Vec<_>>().chunks(CHUNK_SIZE) {
    tokio::spawn(async move {
        for i in chunk {
            small_work(*i).await;
        }
    });
}

6. 使用 Semaphore 限制并发

use tokio::sync::Semaphore;
use std::sync::Arc;

#[tokio::main]
async fn main() {
    let semaphore = Arc::new(Semaphore::new(10));  // 最多 10 个并发
    let mut handles = vec![];
    
    for i in 0..1000 {
        let permit = semaphore.clone().acquire_owned().await.unwrap();
        handles.push(tokio::spawn(async move {
            work(i).await;
            drop(permit);
        }));
    }
    
    for handle in handles {
        handle.await.unwrap();
    }
}

async fn work(i: usize) { }

最佳实践

1. 避免阻塞操作

// ❌ 错误
#[tokio::main]
async fn main() {
    std::thread::sleep(std::time::Duration::from_secs(1));  // 阻塞!
}

// ✅ 正确
#[tokio::main]
async fn main() {
    tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
}

2. 正确使用 Arc

use std::sync::Arc;
use tokio::sync::Mutex;

#[tokio::main]
async fn main() {
    let data = Arc::new(Mutex::new(vec![1, 2, 3]));
    
    let data1 = Arc::clone(&data);
    tokio::spawn(async move {
        let mut guard = data1.lock().await;
        guard.push(4);
    });
}

3. 及时释放锁

use tokio::sync::Mutex;

#[tokio::main]
async fn main() {
    let data = Mutex::new(vec![1, 2, 3]);
    
    // ✅ 好:快速释放锁
    {
        let mut guard = data.lock().await;
        guard.push(4);
    }  // guard 在这里被释放
    
    expensive_operation().await;
    
    // ❌ 不好:持有锁过久
    let mut guard = data.lock().await;
    guard.push(4);
    expensive_operation().await;  // 仍持有锁!
}

async fn expensive_operation() { }

4. 使用 tokio::select! 处理取消

use tokio::sync::oneshot;

#[tokio::main]
async fn main() {
    let (tx, rx) = oneshot::channel();
    
    let handle = tokio::spawn(async move {
        tokio::select! {
            _ = long_running_task() => {
                println!("任务完成");
            }
            _ = rx => {
                println!("任务被取消");
            }
        }
    });
    
    tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
    let _ = tx.send(());  // 取消任务
    
    handle.await.unwrap();
}

async fn long_running_task() {
    tokio::time::sleep(tokio::time::Duration::from_secs(10)).await;
}

5. 错误处理

use anyhow::Result;

#[tokio::main]
async fn main() -> Result<()> {
    let result = tokio::spawn(async {
        do_something().await
    })
    .await??;  // 第一个 ? 处理 JoinError,第二个处理业务错误
    
    Ok(())
}

async fn do_something() -> Result<()> {
    Ok(())
}

本项目示例

主函数

// src/main.rs
use axum::{Router, Server};
use std::net::SocketAddr;

#[tokio::main]  // Tokio 运行时
async fn main() -> anyhow::Result<()> {
    // 初始化日志
    tracing_subscriber::fmt()
        .with_target(false)
        .compact()
        .init();
    
    // 加载配置
    let config = Config::from_env()?;
    
    // 创建数据库连接池(异步)
    let pool = database::create_pool(&config.database_url).await?;
    
    // 初始化数据库(异步)
    database::init_database(&pool).await?;
    
    // 创建 Redis 客户端(异步)
    let cache = RedisCache::new(&config.redis_url).await?;
    
    // 创建应用状态
    let state = Arc::new(AppState { pool, cache });
    
    // 创建路由
    let app = create_routes(state);
    
    // 启动服务器(异步,会一直运行)
    let addr: SocketAddr = format!("{}:{}", config.host, config.port).parse()?;
    tracing::info!("服务器启动于 {}", addr);
    
    Server::bind(&addr)
        .serve(app.into_make_service())
        .await?;
    
    Ok(())
}

数据库连接池

// src/config/database.rs
use sqlx::MySqlPool;

pub async fn create_pool(database_url: &str) -> Result<MySqlPool, sqlx::Error> {
    // Tokio 运行异步数据库连接
    MySqlPool::connect(database_url).await
}

pub async fn init_database(pool: &MySqlPool) -> Result<(), sqlx::Error> {
    // 异步执行 SQL
    sqlx::query(
        "CREATE TABLE IF NOT EXISTS users (
            id BIGINT PRIMARY KEY AUTO_INCREMENT,
            username VARCHAR(255) NOT NULL UNIQUE,
            email VARCHAR(255) NOT NULL UNIQUE,
            password_hash VARCHAR(255) NOT NULL,
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
            updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
        )"
    )
    .execute(pool)
    .await?;
    
    Ok(())
}

服务层

// src/services/user_service.rs
use sqlx::MySqlPool;

pub async fn get_user_by_id(
    pool: &MySqlPool,
    id: i64,
) -> Result<Option<User>, sqlx::Error> {
    // Tokio 运行异步查询
    let user = sqlx::query_as::<_, User>(
        "SELECT id, username, email, password_hash, created_at, updated_at 
         FROM users WHERE id = ?"
    )
    .bind(id)
    .fetch_optional(pool)
    .await?;
    
    Ok(user)
}

Redis 缓存

// src/utils/cache.rs
use redis::AsyncCommands;

pub struct RedisCache {
    client: redis::Client,
}

impl RedisCache {
    pub async fn new(redis_url: &str) -> Result<Self, redis::RedisError> {
        let client = redis::Client::open(redis_url)?;
        
        // 测试连接(异步)
        let mut conn = client.get_async_connection().await?;
        redis::cmd("PING").query_async(&mut conn).await?;
        
        Ok(Self { client })
    }
    
    pub async fn get<T>(&self, key: &str) -> Result<Option<T>, redis::RedisError>
    where
        T: serde::de::DeserializeOwned,
    {
        // Tokio 运行异步 Redis 操作
        let mut conn = self.client.get_async_connection().await?;
        let value: Option<String> = conn.get(key).await?;
        
        Ok(value.and_then(|json| serde_json::from_str(&json).ok()))
    }
    
    pub async fn set<T>(
        &self,
        key: &str,
        value: &T,
        ttl: usize,
    ) -> Result<(), redis::RedisError>
    where
        T: serde::Serialize,
    {
        let json = serde_json::to_string(value).unwrap();
        let mut conn = self.client.get_async_connection().await?;
        conn.set_ex(key, json, ttl).await
    }
}

并发查询示例

// 并发查询多个用户
pub async fn get_users_concurrently(
    pool: &MySqlPool,
    ids: Vec<i64>,
) -> Vec<Option<User>> {
    let mut handles = vec![];
    
    for id in ids {
        let pool = pool.clone();
        let handle = tokio::spawn(async move {
            get_user_by_id(&pool, id).await.ok().flatten()
        });
        handles.push(handle);
    }
    
    let mut results = vec![];
    for handle in handles {
        results.push(handle.await.unwrap());
    }
    
    results
}

常见问题

1. 如何在同步代码中调用异步函数?

// 方式1:使用 block_on
use tokio::runtime::Runtime;

fn sync_function() {
    let rt = Runtime::new().unwrap();
    let result = rt.block_on(async_function());
}

// 方式2:使用 Handle
use tokio::runtime::Handle;

fn sync_function() {
    let handle = Handle::current();
    let result = handle.block_on(async_function());
}

async fn async_function() -> i32 {
    42
}

2. spawn 要求 'static 生命周期怎么办?

// ❌ 错误:引用不是 'static
async fn bad_example(data: &Vec<i32>) {
    tokio::spawn(async {
        println!("{:?}", data);  // 错误!
    });
}

// ✅ 方案1:使用 Arc
use std::sync::Arc;

async fn good_example(data: Arc<Vec<i32>>) {
    tokio::spawn(async move {
        println!("{:?}", data);
    });
}

// ✅ 方案2:克隆数据
async fn clone_example(data: Vec<i32>) {
    let data = data.clone();
    tokio::spawn(async move {
        println!("{:?}", data);
    });
}

3. 如何优雅关闭?

use tokio::signal;

#[tokio::main]
async fn main() {
    let (tx, mut rx) = tokio::sync::mpsc::channel(1);
    
    // 监听关闭信号
    tokio::spawn(async move {
        signal::ctrl_c().await.unwrap();
        println!("收到关闭信号");
        tx.send(()).await.unwrap();
    });
    
    // 主任务
    tokio::select! {
        _ = long_running_task() => {
            println!("任务完成");
        }
        _ = rx.recv() => {
            println!("优雅关闭中...");
        }
    }
}

async fn long_running_task() {
    loop {
        tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
    }
}

总结

Tokio 核心组件

  1. 运行时 - 执行异步任务
  2. 任务 - spawn、JoinSet、spawn_blocking
  3. I/O - TCP、UDP、文件、进程
  4. 同步 - Mutex、RwLock、Semaphore、Barrier
  5. 定时器 - sleep、interval、timeout
  6. 通道 - mpsc、oneshot、broadcast、watch
  7. 工具 - select!、join!、try_join!

何时使用 Tokio

✅ 适合:

  • 网络服务(HTTP、gRPC、WebSocket)
  • 数据库访问
  • 微服务
  • 高并发 I/O

❌ 不适合:

  • CPU 密集计算(使用 rayon)
  • 简单脚本

性能提示

  1. 选择合适的运行时(多线程 vs 单线程)
  2. 使用 spawn_blocking 处理阻塞操作
  3. 合理使用缓冲和批处理
  4. 使用 Semaphore 限制并发
  5. 避免持锁跨 await 点
  6. 及时释放资源

Tokio 是 Rust 异步生态的基石,掌握它对构建高性能应用至关重要!