ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

rust async/await使用示例

2026/8/13 10:56:47 拓冰建站 浏览量
rust async/await使用示例 “救命例”就是能直接抄、跑起来、看到效果的代码。Rust 的async/await乍看像 Go但底层模型完全不同很多 Go 开发者第一次写会掉进“怎么不并发”或“怎么卡住了”的坑。下面给你3 个最常救命的片段从最简单到真实 Web 场景全部可运行。1. 最简异步函数感受await的“让步”rustuse std::time::Duration; use tokio::time::sleep; // 异步函数假装执行 IO 操作 async fn do_something(name: str, secs: u64) - String { println!([{}] 开始睡 {} 秒, name, secs); sleep(Duration::from_secs(secs)).await; // ⚠️ 关键这里会让出线程 format!([{}] 完成了, name) } #[tokio::main] // 启动异步运行时 async fn main() { // 顺序执行跟普通函数一样 let r1 do_something(A, 2).await; let r2 do_something(B, 1).await; println!(顺序结果: {}, {}, r1, r2); }❓ 救什么命让你亲眼看到.await会让出当前任务但顺序执行时不会并发这就是 Go 新手常犯的错——以为所有async fn自动并发。2. 真正的并发对应 Go 的go func()rustuse tokio::time::sleep; use std::time::Duration; async fn do_something(name: str, secs: u64) - String { sleep(Duration::from_secs(secs)).await; format!({} done, name) } #[tokio::main] async fn main() { // 同时启动多个任务类似 go func let handle1 tokio::spawn(do_something(A, 2)); let handle2 tokio::spawn(do_something(B, 1)); // 等待所有任务完成并获取结果 let (r1, r2) tokio::join!(handle1, handle2); println!(并发结果: {:?}, {:?}, r1.unwrap(), r2.unwrap()); }❓ 救什么命tokio::spawn是 Rust 版的go func()但必须 await 或 join 才能拿到结果否则任务会直接被丢弃Rust 不会自动等待。tokio::join!则是同时等待多个 future。3. 真实 Web 场景结合 Axum 处理并发请求这是你最需要的——在 Web 框架中处理异步数据库/HTTP 调用。rustuse axum::{ routing::get, Router, response::Json, }; use serde_json::json; use std::time::Duration; use tokio::time::sleep; // 模拟一个异步的外部 API 调用 async fn fetch_remote_data(id: u32) - String { sleep(Duration::from_millis(500)).await; format!(Data for id {}, id) } // 处理函数必须是异步的 async fn handler(id: u32) - Jsonserde_json::Value { // 并发调用多个外部服务类似 Go 的 WaitGroup let task1 tokio::spawn(fetch_remote_data(id)); let task2 tokio::spawn(fetch_remote_data(id 10)); let (res1, res2) tokio::join!(task1, task2); Json(json!({ result1: res1.unwrap(), result2: res2.unwrap(), })) } #[tokio::main] async fn main() { let app Router::new() .route(/data/:id, get(handler)); // 启动服务 axum::Server::bind(0.0.0.0:3000.parse().unwrap()) .serve(app.into_make_service()) .await .unwrap(); }❓ 救什么命每个请求处理函数都是async框架自动调度。在同一个 handler 里可以用tokio::spawnjoin!实现类似 Go 的扇出/扇入。记住数据库操作、HTTP 请求、文件 IO 都必须用异步版本sqlx::query().fetch_one().await、reqwest::get().await否则会阻塞整个线程池⚠️ 三个最容易“要命”的坑Go 转 Rust 必看Go 习惯Rust 的差异救命写法go func()自动执行tokio::spawn()返回JoinHandle必须.await或join!才能获取结果用let handle tokio::spawn(async { ... }); handle.await?;在 goroutine 里闭包直接捕获变量需要move关键字且变量必须满足static生命周期tokio::spawn(async move { use captured_var });主线程time.Sleep不会阻塞其他 goroutine在异步函数里用std::thread::sleep会阻塞整个运行时线程永远用tokio::time::sleep(...).await✅ 终极救命模板复制即用rustuse tokio::time::{sleep, Duration}; #[tokio::main] async fn main() - Result(), Boxdyn std::error::Error { // 并发执行多个异步操作 let tasks vec![ tokio::spawn(async { sleep(Duration::from_secs(1)).await; one }), tokio::spawn(async { sleep(Duration::from_secs(2)).await; two }), ]; for task in tasks { let result task.await?; println!({}, result); } Ok(()) }把main改成你的 Web 路由处理把sleep换成数据库查询或 HTTP 请求就是一套完整的异步并发处理。如果还有某个具体场景比如超时控制、取消任务、共享状态让你卡住直接说出你的代码片段我帮你改。Rust 异步没那么可怕只是需要“换一个大脑”来理解 —— 你的 Go 经验正是优势只要把go func映射到tokio::spawn把channel映射到tokio::sync::mpsc很快就能上手。加油