568 字
3 分钟
async/await 状态机
原型
// 源码func loadData() async throws -> String { let uid = try await fetchUserID() // await-1 let profile = try await fetchProfile(uid) // await-2 return profile.name}
⸻
伪 C
⚠️ 只保留关键字段;真正产物是 LLVM IR → machine code。
// ⬢ 每个 async 函数对应一个上下文帧(放在堆上)typedef struct { SwiftAsyncContext header; // Swift 运行时代码生成的公共头 uint8_t state; // 状态机标签 Error *error; // 异常槽 String result; // 返回值槽 /* 持久化的局部 */ UserID uid; Profile profile;} LoadDataContext;
/* 编译器展开后的实现,swiftasync 调用约定 */void loadData_swiftasync(LoadDataContext *ctx) { switch (ctx->state) {
case 0: { // 初始态 /* 将“后续步骤”封装成 continuation,传给被等待的函数 */ ctx->state = 1; fetchUserID_swiftasync(/*continuation=*/ctx); return; // ⬅️ 挂起,线程可去干别的 }
case 1: { // await-1 恢复点 if (ctx->error) goto fail; // fetchUserID 报错 ctx->uid = ctx->header.resume_val; ctx->state = 2; fetchProfile_swiftasync(ctx); // 第二个 await return; }
case 2: { // await-2 恢复点 if (ctx->error) goto fail; // fetchProfile 报错 ctx->profile = ctx->header.resume_val; ctx->result = ctx->profile.name; // 计算最终返回值 swift_async_return(ctx); // 触发最外层 .value return; } }
fail: swift_async_throw(ctx, ctx->error); // 向上传播 try/catch}
要点
概念 | 伪 C 中体现 |
---|---|
挂起点 | return 把控制权交回任务调度器 |
状态机 | ctx->state + switch |
Continuation | 上下文指针 ctx 自身即是 continuation |
局部变量跨挂起点 | 提升到 LoadDataContext 成员 |
⸻
Rust 编译器生成的 Future 状态机
// #[allow(…)]: 仅演示enum LoadDataFuture { // 状态枚举 Step0, Step1 { fut_uid: FetchUserID }, // 持久化局部 = 字段 Step2 { uid: UserID, fut_prof: FetchProfile }, Done(Result<String, Error>),}
impl Future for LoadDataFuture { type Output = Result<String, Error>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
loop { match *self { LoadDataFuture::Step0 => { let fut = fetch_user_id(); // 创建子 future *self = LoadDataFuture::Step1 { fut_uid: fut }; }
LoadDataFuture::Step1 { ref mut fut_uid } => { match fut_uid.poll(cx) { Poll::Pending => return Poll::Pending, // 挂起 Poll::Ready(id) => { let fut = fetch_profile(id?); *self = LoadDataFuture::Step2 { uid: id?, fut_prof: fut }; } } }
LoadDataFuture::Step2 { ref mut fut_prof, .. } => { match fut_prof.poll(cx) { Poll::Pending => return Poll::Pending, Poll::Ready(profile) => { *self = LoadDataFuture::Done(Ok(profile?.name)); return Poll::Ready(Ok(profile?.name)); } } }
LoadDataFuture::Done(ref out) => return Poll::Ready(out.clone()), } } }}
你看到的 await ➜ poll(cx) 环就是 回调 + 状态机 的另一种等价实现。
⸻
- 编译期 把顺序写法拆成「switch-驱动的状态机」。
- 运行时 用 continuation/Future::poll 把任务挂起、排队,事件就绪后再恢复。
- 写出来像同步,执行方式仍完全异步,靠调度器节约线程。
async/await 状态机
https://blog.lpkt.cn/posts/async-await-state-mach/