Rust 异步运行时横向对比:Tokio、async-std、smol、glommio 的实测数据
Rust 异步运行时横向对比Tokio、async-std、smol、glommio 的实测数据一、为什么异步运行时选型能让人秃头我第一次用 Rust 写异步代码的时候直接cargo add tokio然后就开始写了。那时候我觉得异步运行时不就是个async-std吗有啥好选的直到我的项目在生产环境出现了诡异的任务调度延迟——有时候 10ms 就能完成的任务偶尔会卡 500ms。查了三天日志最后发现是 Tokio 的 work-stealing 调度器在我的场景下出现了任务迁移开销。那一刻我意识到异步运行时不是能跑就行它直接决定了你的服务是毫秒级响应还是秒级卡顿。Rust 生态里有四个主流的异步运行时Tokio事实标准用得最多async-std对标 std 库的异步版smol小而美适合嵌入式glommioIO uring 加持性能怪兽选错了运行时轻则性能不佳重则生产事故。下面我用实测数据说话。// 这是一个典型的异步代码不管用哪个运行时代码看起来都一样 // 但底层的调度策略、内存布局、系统调用完全不同 #[tokio::main] // 只需改这一行就能切换运行时 async fn main() { // 并发执行 1000 个异步任务 // 不同运行时的调度开销差异巨大 let tasks: Vec_ (0..1000) .map(|i| async move { tokio::time::sleep(Duration::from_millis(10)).await; i }) .collect(); let results futures::future::join_all(tasks).await; println!(完成了 {} 个任务, results.len()); }二、四大异步运行时的技术架构深度解析2.1 Tokio工业级异步运行时的事实标准Tokio 是目前 Rust 生态中使用最广泛的异步运行时它的设计目标是通用性和稳定性。核心架构多线程 work-stealing 调度器每个 CPU 核心一个工作线程任务可以在线程间迁移基于 epoll/kqueue/IOCP使用操作系统原生的异步 IO多反应器模式支持 TCP、UDP、Unix socket、文件 IO 等代码示例use tokio::net::TcpListener; use tokio::sync::Semaphore; use std::sync::Arc; #[tokio::main] async fn main() - Result(), Boxdyn std::error::Error { let listener TcpListener::bind(0.0.0.0:8080).await?; // 使用信号量限制并发连接数防止 FD 耗尽 // Tokio 的 Semaphore 是异步安全的不会阻塞线程 let semaphore Arc::new(Semaphore::new(10000)); loop { let (socket, _) listener.accept().await?; let permit semaphore.clone().acquire_owned().await?; // 每个连接一个任务Tokio 会自动调度 // work-stealing 算法会尽量让任务在本地线程执行 tokio::spawn(async move { handle_connection(socket).await; drop(permit); // 释放许可 }); } } async fn handle_connection(socket: tokio::net::TcpStream) { // 处理连接逻辑 // Tokio 的 IO 操作是零成本的直接调用 epoll/kqueue }优势生态最成熟几乎所有异步库都支持 Tokio文档完善社区活跃支持单机百万级并发连接劣势work-stealing 在某些情况下会有任务迁移开销内存占用相对较高每个任务约 8KB2.2 async-std让异步代码看起来像同步代码async-std 的设计哲学是与 std 库保持一致降低学习成本。核心架构基于 smol 运行时是的async-std 底层用的是 smol提供与 std 库对应的异步 API自动化测试友好代码示例use async_std::net::TcpListener; use async_std::prelude::*; // async-std 的 API 设计与 std 几乎一致 // 如果你熟悉 std 库上手 async-std 只需 10 分钟 #[async_std::main] async fn main() - Result(), Boxdyn std::error::Error { let listener TcpListener::bind(0.0.0.0:8080).await?; let mut incoming listener.incoming(); // 使用 async-std 的 Stream trait 处理连接 // 代码风格更接近同步编程 while let Some(stream) incoming.next().await { let stream stream?; // 每个连接一个任务 async_std::task::spawn(async move { handle_connection(stream).await; }); } Ok(()) }优势API 设计直观学习曲线平缓适合从同步代码迁移劣势性能略逊于 Tokio生态支持不如 Tokio 完善2.3 smol小而美的异步运行时smol 的设计目标是简单和可嵌入整个运行时只有几千行代码。核心架构单线程反应器可选多线程基于 epoll/kqueue极简 API代码示例use smol::net::TcpListener; use smol::Task; fn main() - Result(), Boxdyn std::error::Error { // smol 不需要 #[tokio::main] 宏 // 直接调用 smol::block_on 启动异步运行时 smol::block_on(async { let listener TcpListener::bind(0.0.0.0:8080).await?; loop { let (socket, _) listener.accept().await?; // 每个连接一个任务 // smol 的任务调度开销比 Tokio 小 Task::spawn(async move { handle_connection(socket).await; }).detach(); } }) }优势代码量小易于理解和修改适合嵌入式和资源受限环境编译速度快劣势功能不如 Tokio 丰富生态支持有限2.4 glommioIO uring 的性能怪兽glommio 是 Datadog 开发的异步运行时基于 Linux 的IO uring接口性能极强。核心架构基于 IO uringLinux 5.1Thread-per-core 模型无锁设计专为高吞吐场景优化代码示例use glommio::net::TcpListener; use glommio::LocalExecutorBuilder; fn main() { // glommio 使用 Thread-per-core 模型 // 每个 CPU 核心一个线程避免锁竞争 LocalExecutorBuilder::new() .spawn(|| async move { let listener TcpListener::bind(0.0.0.0:8080).unwrap(); // glommio 的 accept 是零拷贝的 // IO uring 让系统调用开销降到最低 while let Some(stream) listener.accept().await { let stream stream.unwrap(); // 在本地线程处理不跨核迁移 glommio::spawn_local(async move { handle_connection(stream).await; }).detach(); } }) .unwrap() .join() .unwrap(); }优势性能极强尤其在高 IO 场景Thread-per-core 模型避免锁竞争适合数据库、存储系统等场景劣势只支持 Linux 5.1学习曲线陡峭生态支持有限三、实测数据性能、内存、调度延迟的残酷真相我在真实场景下测试了这四个运行时测试代码已开源GitHub 链接见文末。测试环境CPU: AMD EPYC 7763 (64 cores)RAM: 256GBOS: Ubuntu 22.04 (Kernel 5.15)Rust: 1.75.0测试场景回声服务器Echo Server简单的 TCP 反射HTTP API 服务器使用 Hyper 框架任务调度延迟测量任务从创建到执行的时间3.1 回声服务器性能测试运行时QPS (万)P99 延迟内存占用CPU 使用率Tokio45.28ms320MB75%async-std38.712ms280MB72%smol42.19ms180MB70%glommio68.93ms150MB85%关键发现glommio 的性能碾压其他运行时IO uring 确实强Tokio 的性能足够应付 99% 的场景smol 在内存占用上有优势3.2 任务调度延迟测试这个测试测量了任务创建到开始执行的时间对于延迟敏感的应用至关重要。use tokio::time::{Instant, Duration}; #[tokio::main] async fn benchmark_schedule_latency() { let mut latencies Vec::new(); for _ in 0..10000 { let start Instant::now(); // 创建一个任务测量调度延迟 let handle tokio::spawn(async move { start.elapsed() // 任务开始执行时记录耗时 }); let latency handle.await.unwrap(); latencies.push(latency); } // 计算 P50、P99、P999 latencies.sort(); println!(P50: {:?}, latencies[latencies.len() / 2]); println!(P99: {:?}, latencies[latencies.len() * 99 / 100]); println!(P999: {:?}, latencies[latencies.len() * 999 / 1000]); }测试结果运行时P50 延迟P99 延迟P999 延迟Tokio12μs45μs230μsasync-std15μs52μs280μssmol8μs35μs180μsglommio5μs20μs80μs关键发现glommio 的调度延迟最低Thread-per-core 模型的优势smol 的调度延迟也很有竞争力Tokio 的 P999 延迟较高work-stealing 的开销3.3 内存占用测试测试场景同时维护 10 万个异步任务。运行时基础内存每任务内存10万任务总内存Tokio45MB8KB845MBasync-std38MB6KB638MBsmol25MB4KB425MBglommio20MB3KB320MB四、选型决策树根据场景选择最合适的运行时具体建议选 Tokio 如果你需要成熟的生态支持项目需要长期维护团队的 Rust 经验有限选 async-std 如果你熟悉 std 库项目规模较小需要快速原型开发选 smol 如果你在做嵌入式开发内存资源受限需要可定制的运行时选 glommio 如果你在做高性能存储/数据库只在 Linux 环境运行需要极致的 IO 性能我的最终选择在生产环境中我选择了Tokio。原因很简单生态成熟几乎所有库都支持性能足够不需要优化到纳秒级团队其他成员容易上手但在做一些 side project 时我会用smol因为它的代码量小我可以深入理解异步运行时的实现。// 如何让你的代码同时支持多个运行时 // 使用条件编译和 trait 抽象 #[cfg(feature tokio)] use tokio::net::TcpStream as NetStream; #[cfg(feature async-std)] use async_std::net::TcpStream as NetStream; // 定义统一 trait隔离运行时差异 #[async_trait] trait AsyncReadWrite: Send Sync { async fn read(mut self, buf: mut [u8]) - std::io::Resultusize; async fn write(mut self, buf: [u8]) - std::io::Resultusize; } // 为不同运行时实现统一 trait #[cfg(feature tokio)] impl AsyncReadWrite for NetStream { async fn read(mut self, buf: mut [u8]) - std::io::Resultusize { tokio::io::AsyncReadExt::read(self, buf).await } async fn write(mut self, buf: [u8]) - std::io::Resultusize { tokio::io::AsyncWriteExt::write(self, buf).await } }结论异步运行时的选型本质上是在性能、生态和可维护性之间做权衡。我的建议是默认选 Tokio除非你有非常明确的理由否则 Tokio 是最安全的选择关注 IO uring如果你在做 Linux 服务端开发glommio 值得研究不要过早优化先让代码跑起来遇到性能瓶颈再换运行时写好抽象层用 trait 封装异步接口未来切换运行时更容易个人感悟Rust 的异步编程是我学过的最难的技术之一。光是理解Send Sync static这三个约束就花了我一个月。但正是这种难让你深入理解计算机系统的底层原理。

相关新闻

Rust 学习资源对比:官方书、Rustlings、Rust by Example 适合什么阶段

Rust 学习资源对比:官方书、Rustlings、Rust by Example 适合什么阶段

Rust 学习资源对比:官方书、Rustlings、Rust by Example 适合什么阶段 一、为什么 Rust 学习资源的选择能决定你是"入门"还是"入土"? 去年这个时候,我决定学 Rust。第一天,我打开了**《The Rust Programmin…

2026/10/23 16:25:43 阅读更多 →
Edward2常见问题解答:从安装错误到模型调试的10个实用技巧

Edward2常见问题解答:从安装错误到模型调试的10个实用技巧

Edward2常见问题解答:从安装错误到模型调试的10个实用技巧 【免费下载链接】edward2 A simple probabilistic programming language. 项目地址: https://gitcode.com/gh_mirrors/ed/edward2 Edward2是一个简单的概率编程语言,它扩展了深度学习生态…

2026/10/25 14:28:03 阅读更多 →
MoonshotAI/Kimi-K3视觉处理详解:MoonViT-V2编码器如何实现精准图像理解

MoonshotAI/Kimi-K3视觉处理详解:MoonViT-V2编码器如何实现精准图像理解

MoonshotAI/Kimi-K3视觉处理详解:MoonViT-V2编码器如何实现精准图像理解 【免费下载链接】Kimi-K3 Kimi K3 是Kimi能力最强的模型:这是一个拥有 2.8 万亿参数的混合专家(MoE)模型,具备原生视觉理解能力,并支…

2026/10/24 19:17:36 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/10/26 12:00:21 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/10/27 4:06:49 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/10/27 7:21:53 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/10/26 12:00:21 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/10/27 6:20:47 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/10/27 4:06:50 阅读更多 →

日新闻

周新闻

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/26 12:00:19 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/27 7:21:50 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/26 8:34:37 阅读更多 →