异步编程主要用于高并发 I/O 密集型任务;Rust 的异步模型基于 Future + Polling,在单线程上即可完成数千个并发任务。async/.await是Rust内置语法,用于让异步函数编写得像同步代码。async将代码块转化成实现了Future trait 的状态机。
async
async 是用于创建 Future 的语法糖,用来标记一个函数为异步函数:
- 异步函数(
async fn):调用后不会立即执行,而是返回一个 Future- 返回值会被自动包装为 Future;
- 异步函数内部可以直接使用
.await; - 异步函数的参数支持所有普通函数的参数类型(包括引用、所有权类型等),但要注意生命周期;
- 异步块(
async { ... }):async块可以捕获外部变量(类似闭包)async { ... }:默认像闭包捕获,按借用捕获外部变量;async move { ... }:把需要的变量按值move进 Future,Future 对它们具有所有权。
- 异步闭包
// 异步函数
async fn fetch_data() -> u32 {
42
}
// 异步块
let fut = async {
println!("Working...");
100
};
// 异步闭包
let async_func = async |x: i32| x + 1;
.await
.await 是用于等待 Future 执行完成的操作符;只能在async函数或async块内部使用。
对 Future 调用 .await,会暂停当前 Future 的执行(并将线程让给其他可执行的 Future),直到被等待的 Future 完成,然后返回其 Output 结果。
Rust中代码编译扫描时,把每一个可能“挂起”的 .await 看作一个边界,把整个函数拆成几段;同时定义状态机,把后续要继续执行所需的局部变量 保存下来。
// 原始示例函数
async fn foo() -> i32 {
let x = 1;
let y = async { 2 }.await;
let z = x + y;
let w = async { z * 10 }.await;
w
}
//////////////////////////////////////////
// 翻译的伪代码
enum FooState {
// 初始状态
Start,
// 正在等待第一个 .await: async { 2 }
AwaitY {
// 需要保存仍然会用到的局部变量
x: i32,
// 正在等待的子 future
fut_y: FutY,
},
// 正在等待第二个 .await: async { z * 10 }
AwaitW {
// 计算 w 之前需要的变量
z: i32,
fut_w: FutW,
},
// 已经完成(再 poll 就是错误)
Done,
}
// 整个 async 块对应的 Future 类型
struct FooFuture {
state: FooState,
}
// 子 future 的具体类型编译器会生成匿名类型,这里用伪名代替
type FutY = impl Future<Output = i32>;
type FutW = impl Future<Output = i32>;
// 核心状态机
impl Future for FooFuture {
type Output = i32;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
// 安全地拿到可变引用
let this = unsafe { self.get_unchecked_mut() };
loop {
match &mut this.state {
FooState::Start => {
// 1. 执行:let x = 1;
let x = 1;
// 2. 创建第一个子 Future:async { 2 }
let fut_y: FutY = async { 2 };
// 3. 进入 AwaitY 状态,保存需要的变量
this.state = FooState::AwaitY { x, fut_y };
// loop 继续,会立刻进入下一轮 match(相当于“尾递归优化”)
}
FooState::AwaitY { x, fut_y } => {
// 尝试推进子 future
match Pin::new(fut_y).poll(cx) {
Poll::Pending => {
// 子 future 还没好:当前 async 函数整体也只能 Pending
return Poll::Pending;
}
Poll::Ready(y) => {
// some_future().await 完成,得到了 y
// 3. 计算 z = x + y
let z = *x + y;
// 4. 创建第二个子 Future:async { z * 10 }
let fut_w: FutW = async { z * 10 };
// 5. 切换到 AwaitW 状态
this.state = FooState::AwaitW { z, fut_w };
// 再次进入 loop,转到下一个 match 分支
}
}
}
FooState::AwaitW { z, fut_w } => {
// 推进第二个子 future
match Pin::new(fut_w).poll(cx) {
Poll::Pending => {
return Poll::Pending;
}
Poll::Ready(w) => {
// 第二个 await 完成,最终结果就是 w
this.state = FooState::Done;
return Poll::Ready(w);
}
}
}
FooState::Done => {
panic!("poll called after completion");
}
}
}
}
}
Future
Future (std::future::Future)是 Rust 异步编程的基础,async 语法的本质是生成 Future,.await 则是触发 Future 执行并等待结果。
trait Future {
// Future 最终产生的结果类型
type Output;
// 驱动 Future 执行:返回 Poll<Output>
// waker:用于唤醒暂停的 Future
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
}
// Poll 枚举:表示 Future 的执行状态
enum Poll<T> {
// Future 仍在执行中(需要等待某个事件,如 IO 完成)
Pending,
// Future 已完成,返回结果 T
Ready(T),
}
Future 是惰性的—— 定义后不会自动执行,必须通过 poll 方法 “驱动” 它运行。只有当调用者(通常是异步执行器)调用 poll 时,Future 才会推进执行,直到遇到 “需要等待的事件”(如网络请求、文件 IO),此时返回 Pending 并暂停,等待被 waker 唤醒后再次执行。
执行器
要运行一个异步函数(async fn),必须使用一个 执行器(Runtime / Executor) 来驱动它
| 场景 | 解决方法 | 代码示例 |
|---|---|---|
| 应用程序入口 | 使用宏 | #[tokio::main]async fn main() { ...} |
| 普通函数中 | 手动创建 Runtime | Runtime::new().unwrap().block_on(future) |
| 轻量级/测试 | 使用简单执行器 | futures::executor::block_on(future) |
async/.await 本身是串行的,若要并发执行多个 Future,需使用并发宏:
tokio::join!/async_std::future::join!:等待所有 Future 完成(类似 Promise.all);tokio::select!/async_std::future::select!:等待第一个完成的 Future(类似 Promise.race);tokio::try_join!:并发执行,且所有 Future 均返回Result,一旦有一个失败则立即返回错误。
运行时(Runtime)
运行时是驱动异步任务(Future)执行的 “引擎”,负责线程池管理、任务调度、IO 事件复用(如 epoll/kqueue)等底层工作:
- Executor(执行器)
- 负责不断调用
Future::poll()推进任务执行。 - 支持任务调度、任务队列、线程池等。
- 负责不断调用
- Reactor(反应器)
- 基于操作系统的 IO 多路复用机制(epoll/Linux、kqueue/macOS、IOCP/Windows)。
- 当 socket、文件或计时器可用时,唤醒对应任务。
- Concurrency Primitives(并发原语)
- 提供异步锁(如
Mutex)、通道(Channel)、计时器(Timer)等工具,支持多任务安全通信。
- 提供异步锁(如
常见运行时库:

| 特性 | Tokio | async-std | smol |
|---|---|---|---|
| 性能 | 最高(多线程调度) | 中等 | 轻量,适中 |
| 使用体验 | 偏工程化、配置丰富 | 最接近标准库 | 极简、底层 |
| 生态支持 | 最强(hyper, tonic, reqwest) | 中等 | 少量核心库 |
| 内部实现 | work-stealing + reactor | smol 内核 | 模块化组件 |
| 适合场景 | 高并发服务端 | 快速开发、教学 | 小型嵌入式、自定义运行时 |
1230

被折叠的 条评论
为什么被折叠?



