Rust 异步编程简介
异步编程是一种允许执行输入输出操作(网络请求、文件读取、数据库操作)而不阻塞主执行流程的编程范式。在 Rust 中,异步性通过 Future 系统和 async/await 关键字实现。与多线程不同,异步代码在单个线程中运行,在等待期间在任务之间切换。
在本教程中,我们将介绍:
- Rust 中
async/await的基础知识 - 使用
tokiocrate——最流行的异步运行时 - 创建和组合
Future - 实际示例:异步 HTTP 客户端和定时器
本文面向熟悉 Rust 基本语法的开发者。如果您是初学者——建议先通过 PythonLib 学习语言基础。
Rust 中 async/await 和 Future 的基础知识
什么是 Future?
Future 是一个 trait,表示一个将来可能完成的异步操作。在 Rust 中,Future 是惰性的:在被轮询(poll)之前它什么也不做。轮询由异步运行时(例如 Tokio)负责。
一个简单的异步函数示例:
use std::time::Duration;
async fn say_hello() { println!("来自异步世界的问候!"); tokio::time::sleep(Duration::from_secs(1)).await; println!("1 秒过去了");}
#[tokio::main]async fn main() { say_hello().await;}async 关键字将函数转换为 Future。调用 .await 会暂停当前任务的执行,直到 Future 完成,而不会阻塞线程。
异步任务的生命周期
当您调用 .await 时,会发生以下情况:
- 运行时轮询 Future(调用
poll()方法) - 如果 Future 已就绪——返回结果
- 如果 Future 正在等待(例如网络操作)——运行时切换到另一个任务
- 当资源可用时,运行时恢复任务
Rust 的一个重要特性:.await 只能在异步函数或 async {} 块内部调用。尝试在同步上下文中使用它会导致编译错误。
Tokio 的实际使用
安装和配置
Tokio 是 Rust 的异步运行时,提供任务调度器、定时器、网络套接字等功能。首先,在 Cargo.toml 中添加:
[dependencies]tokio = { version = "1", features = ["full"] }features = ["full"] 标志启用 Tokio 的所有功能。对于生产环境,最好只选择必要的特性。
运行多个异步任务
异步的主要优势之一是并行执行多个任务。使用 tokio::spawn 在后台启动任务:
use tokio::time::{sleep, Duration};
async fn task(name: &str, seconds: u64) { println!("任务 {} 开始", name); sleep(Duration::from_secs(seconds)).await; println!("任务 {} 在 {} 秒后完成", name, seconds);}
#[tokio::main]async fn main() { let handle1 = tokio::spawn(task("A", 2)); let handle2 = tokio::spawn(task("B", 1));
// 等待两个任务完成 let _ = tokio::join!(handle1, handle2); println!("所有任务已完成");}tokio::join! 宏等待所有传入的 Future 完成。如果一个任务提前完成,执行不会中断——我们会等待其余任务。