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/