async-std 死了,Tokio 赢了,但 smol 正在悄悄吃市场

2025 年 8 月,RUSTSEC-2025-0052 正式发布:async-std 官方停更,无补丁、无维护、无未来。如果你现在还在生产项目里用 async-std,某种程度上等于在用过期的依赖。

这不是突然发生的。async-std 早在 2023 年之后更新频率就断崖式下滑,社区里早就传它「已经在重症监护室了」。但官方公告把这件事彻底公开了——Rust 异步生态就此少了一个玩家。


三年三选一,现在变成两个

Rust 的 async/.await 只是语言层面的语法,真正的「谁来跑这些 Future」取决于你选哪个运行时。很长一段时间里,Rust 工程师选运行时就是在做三选一:

  • Tokio:全能型,生态最完整,几乎所有主流框架(Axum、Hyper、Tonic)都 built on Tokio
  • async-std:标准库镜像型,API 设计贴近 std,上手最友好
  • smol:极简型,代码少、可组合、不绑架你的依赖树

async-std 停更之后,三选一变成了二选一:Tokio 或 smol。


Tokio 现在有多 dominant?

数字最能说明问题。

根据 2026 State of Rust 调查:

指标 Tokio async-std(生前) smol
生产项目采用率 78% 14% 8%
crates.io 周下载 5800 万次 1200 万次 280 万次
GitHub Stars 26,400 3,900 4,100
生态库兼容性 Axum/Hyper/Tonic/Reqwest 全支持 仅部分 通过 async-adapter 兼容

Tokio 的生态壁垒已经是铁板一块。你想在 Rust 里写 HTTP 服务?用 Axum。写 gRPC?用 Tonic。写数据库驱动?用 SQLx。它们全都只认 Tokio。在这种局面下,选其他 runtime 的代价不只是「少一些库」,而是「核心依赖全要自己造轮子」。


但 smol 正在吃 async-std 的遗产

async-std 的作者 Stjepan Glavina 同时也是 smol 的核心维护者。停更公告里明确推荐 smol 作为迁移目标。

这不是巧合——smol 本质上是 async-std 的精神继承者,但设计更干净:

// smol 的哲学:小于 1500 行代码,整个运行时你可以读完
use smol::{Async, TcpListener};
use std::net::TcpStream;

fn main() -> std::io::Result<()> {
    smol::block_on(async {
        let listener = Async::<TcpListener>::bind(("127.0.0.1", 8080))?;
        loop {
            let (stream, _) = listener.accept().await?;
            smol::spawn(async move {
                let mut buf = [0u8; 1024];
                while let Ok(n) = stream.read(&mut buf).await {
                    if n == 0 { break; }
                    stream.write_all(&buf[..n]).await.unwrap();
                }
            }).detach();
        }
        Ok(())
    })
}

smol 的优势在于「不强迫你接受它的全部」。你可以只用它的 executor,换成自己的 reactor;也可以只拿它的 async I/O 层,接到 Tokio 上去。这对写库的人来说非常重要——你的库不应该强制用户接受某个特定运行时。


2026 年的 benchmark 差距还重要吗?

有一个反直觉的事实:大多数应用场景下,runtime 性能差距根本不是瓶颈。

johal.in 的 2026 年实测数据(c7g.4xlarge AWS 实例,16 vCPU):

指标 Tokio 1.38 async-std 1.12 smol 2.4
TCP echo 吞吐量 142k req/s 116k req/s 100k req/s
p99 延迟(10k 并发) 82µs 104µs 128µs
50k 空闲任务内存 142MB 118MB 88MB

Tokio 在高并发场景下确实领先,smol 的内存占用最低。但 82µs vs 128µs 的 p99 延迟差,在实际业务里能感知到的场景屈指可数——除非你真的是高性能网络基础设施,否则选哪个 runtime 不会是你的性能瓶颈。

真正的成本在于:你的 runtime 拉进来多少依赖。Tokio 全功能开启大概拉进来 50 个 crate,smol 只需要 5 个。如果你做嵌入式或者在意编译时间,这反而是选 smol 的理由。


现在怎么选

场景 推荐
生产级 HTTP/gRPC 服务 Tokio
写一个对外发布的库 smol
嵌入式 / no_std embassy(不在本次讨论范围)
CLI 工具,需要编译快、依赖少 smol
学习 async Rust smol(代码少好读)或 async-std 遗产(已有项目)

如果你现在还在用 async-std,审计一下依赖树,计划迁移。Tokio 是最稳妥的生产选择;smol 是轻量场景和库开发的好选择。

async-std 的死亡不是生态的倒退,而是某种意义上的简化——少一个选择,少一分兼容性顾虑。Tokio 统治,smol 补位,Rust async 的故事在 2026 年反而更清晰了。


下一步

  1. 查一下自己的 Cargo.toml,有没有 async-std 依赖,有就计划迁移
  2. 写库的时候优先用 runtime-agnostic 的 async trait,别假定用户用哪个 runtime
  3. 生产项目直接用 Tokio,生态成熟度和社区支持都是现成的护城河

评论区

0 条评论

登录后可评论。

铁锈·Rust工具链 15 阅读