为什么 Rust 需要异步编程

Rust 的异步编程模型建立在 Future trait 之上,提供了零成本抽象的执行器(executor)和反应器(reactor)。

Future trait 核心

rust
pub trait Future {
    type Output;
    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
}

poll 方法被反复调用,直到返回 Poll::Ready

async/await 语法糖

rust
async fn fetch_data(url: &str) -> Result<String, Error> {
    let response = reqwest::get(url).await?;
    let body = response.text().await?;
    Ok(body)
}

async fn 会自动返回一个实现了 Future 的匿名类型。

常见模式

1. 并发请求

rust
let (user, posts) = futures::join!(fetch_user(), fetch_posts());

2. 超时控制

rust
let result = tokio::time::timeout(
    Duration::from_secs(5),
    async_operation()
).await?;

3. 选择器

rust
tokio::select! {
    _ = timeout => println!("timeout"),
    val = receiver.recv() => println!("got: {}", val),
}

运行时选择

Runtime 特点 适用场景
Tokio 功能最全,生态丰富 网络服务、复杂异步应用
async-std 标准库风格 API 学习、简单项目
smol 轻量级 嵌入式、资源受限

性能对比

在 10k 并发连接的基准测试中:

  • Tokio:~120k 请求/秒
  • async-std:~95k 请求/秒
  • 同步:~45k 请求/秒

异步带来的吞吐量提升显著。

踩坑指南

Pinning 问题Pin<Box<dyn Future>>dyn Future 场景下必须使用 Box::pin()

Send + Sync:跨线程任务必须满足这两个 trait,否则编译报错。

阻塞操作:在异步上下文中调用同步阻塞函数会导致整个执行器卡死。

小结

Rust 异步编程学习曲线陡峭,但掌握后能写出高性能的并发程序。建议从小项目开始,逐步深入。