Rust - async/await

Rust 的 async/await 语法是编写异步代码的核心工具,它允许我们用类似同步代码的风格编写高性能的非阻塞代码。


1. 核心概念

  • 异步编程:在等待 I/O 操作(网络、文件读写等)时让出 CPU,避免阻塞线程。
  • Future trait :所有异步操作的基础,代表一个可能尚未完成的计算(类似 JavaScript 的 Promise)。
  • 执行器 (Executor) :调度和执行异步任务(如 tokioasync-std)。

2. 基本语法

(1) 定义异步函数

rust 复制代码
// 使用 `async fn` 定义异步函数
async fn fetch_data() -> String {
    // 模拟异步操作(如网络请求)
    "Hello, async!".to_string()
}
  • 返回值:async fn 返回一个实现了 Future<Output = String> 的类型(而非直接返回 String)。

(2) 等待异步结果:.await

rust 复制代码
async fn process() {
    // 使用 .await 等待异步操作完成(不阻塞线程)
    let data = fetch_data().await;
    println!("{}", data); // 输出: "Hello, async!"
}
  • .await 只能在 async 函数/块中使用。
  • 执行到 .await 时,若 Future 未完成,会让出控制权给执行器。

3. 异步代码的执行

步骤 1:创建异步运行时

rust 复制代码
#[tokio::main] // 使用 tokio 运行时
async fn main() {
    process().await;
}
  • 需要第三方运行时(如 tokioasync-std)驱动 Future 的执行。

步骤 2:执行器工作流程

  1. 调用 process() 返回一个未执行的 Future
  2. .await 触发 Future 的轮询(poll)。
  3. Future 阻塞(如等待网络),执行器挂起任务并执行其他任务。
  4. 事件就绪时(如收到网络响应),执行器唤醒任务继续执行。

4. 关键特性

(1) 零成本抽象

  • Rust 的 async/await 在编译时转换为状态机,几乎没有运行时开销。

(2) 无堆内存分配(可选)

  • 简单 async 函数可在栈上分配状态,避免堆分配(如 no_std 环境)。

(3) 协作式调度

  • 任务通过 .await 主动让出控制权,需避免长时间阻塞:

    rust 复制代码
    // 错误:阻塞线程的操作!
    async fn bad_example() {
        std::thread::sleep(Duration::from_secs(2)); // 阻塞整个线程
    }
    
    // 正确:使用非阻塞等待
    async fn good_example() {
        tokio::time::sleep(Duration::from_secs(2)).await; // 让出控制权
    }

5. 组合异步任务

(1) 并发执行

rust 复制代码
use tokio::join;

async fn task_one() { /* ... */ }
async fn task_two() { /* ... */ }

async fn run_concurrent() {
    // 同时执行两个任务,等待全部完成
    let (result1, result2) = join!(task_one(), task_two());
}

(2) 选择最先完成的任务

rust 复制代码
use tokio::select;

async fn race_tasks() {
    select! {
        _ = task_one() => println!("Task 1 won"),
        _ = task_two() => println!("Task 2 won"),
    }
}

6. 错误处理

  • 与同步代码一致,使用 Result?
rust 复制代码
async fn fetch() -> Result<String, reqwest::Error> {
    let resp = reqwest::get("https://example.com").await?;
    resp.text().await
}

7. 底层原理:状态机转换

编译后,async 函数被转换为状态机:

rust 复制代码
// 伪代码:fetch_data() 编译后的状态机
enum FetchDataFuture {
    Start,
    Waiting(NetworkRequest),
    Done,
}

impl Future for FetchDataFuture {
    fn poll(&mut self) -> Poll<String> {
        match self {
            Start => {
                let request = start_network_request();
                *self = Waiting(request);
                Poll::Pending // 首次轮询未完成
            }
            Waiting(request) => {
                if request.is_ready() {
                    let data = request.get_data();
                    *self = Done;
                    Poll::Ready(data) // 完成时返回结果
                } else {
                    Poll::Pending // 继续等待
                }
            }
            Done => panic!("Future already completed"),
        }
    }
}

总结

特性 说明
async fn 定义异步函数,返回 Future
.await 等待 Future 完成(非阻塞)
执行器 (Executor) 驱动 Future 运行(如 tokio
零成本抽象 编译为高效状态机,无额外运行时开销
协作式调度 任务需主动让出 CPU,避免长阻塞操作

通过 async/await,Rust 在保证安全性和性能的同时,提供了直观的异步编程体验。

相关推荐
芳草萋萋鹦鹉洲哦5 小时前
【vue3+tauri+rust】如何实现下载文件mac+windows
windows·macos·rust
寻月隐君13 小时前
Rust 异步编程实践:从 Tokio 基础到阻塞任务处理模式
后端·rust·github
萧曵 丶17 小时前
Rust 中的返回类型
开发语言·后端·rust
浪裡遊19 小时前
Sass详解:功能特性、常用方法与最佳实践
开发语言·前端·javascript·css·vue.js·rust·sass
受之以蒙20 小时前
Rust & WASM 之 wasm-bindgen 基础:让 Rust 与 JavaScript 无缝对话
前端·笔记·rust
Elixin20 小时前
第一章:环境搭建
rust
Pomelo_刘金2 天前
Rust 宣布发布1.88.0
rust
寻月隐君2 天前
告别 Vec!掌握 Rust bytes 库,解锁零拷贝的真正威力
后端·rust·github
大卫小东(Sheldon)2 天前
GIM 1.5发布了! 支持Windows系统了
git·ai·rust
寻月隐君2 天前
告别竞态条件:基于 Axum 和 Serde 的 Rust 并发状态管理最佳实践
后端·rust·github