. 总结与延伸阅读

串联 Rust 异步机制从编译期变换到运行期调度的全景图,汇总核心术语与延伸资料.

回顾这五篇文章,Rust 的 async async / await await 将编译期代码变换、所有权与类型约束以及库级事件循环三者结合在一起:

  1. 资源与模型选择( 为什么需要异步 ): 为了在不引入强制运行时和动态栈管理的前提下支持高并发等待,Rust 放弃了有栈协程与基于回调推送的模型,选择了基于轮询拉取的无栈协程. 这使得嵌套异步调用能够内联为单一状态机结构体,并以直接 drop drop 状态机的方式免费获得了同步取消能力.
  2. 轮询与唤醒契约( Future 与 Waker ): 标准库用 Future::poll Future::poll 和 Poll<T> Poll<T> 规定了推进状态机的统一接口,用 Context Context 与 Waker Waker 解耦了“驱动状态机”和“监听外部事件”. RawWaker RawWaker 与 RawWakerVTable RawWakerVTable 通过手工构造的双字长胖指针,在不依赖堆分配和泛型传染的条件下实现了跨执行器的类型擦除.
  3. 编译期状态机变换( async/await 脱糖 ): 编译器按 .await .await 挂起点切分控制流,分析跨越挂起点存活的局部变量,将顺序代码改写为实现了 Future Future 的带标签联合体( enum enum ). 理解这一内存布局,就能直接推导状态机的体积变化、递归 async fn async fn 的间接层需求,以及跨 .await .await 持有非 Send Send 锁守卫带来的编译错误.
  4. 自引用安全边界( Pin 与自引用结构 ): 当局部变量借用跨越 .await .await 时,状态机内部会出现指向自身其他字段的自引用指针. Pin<P> Pin<P> 通过在类型层面限制安全代码获取 !Unpin !Unpin 对象的 &mut T &mut T ,阻止了在首次 poll poll 之后通过 mem::swap mem::swap 按位搬移状态机,从而在零运行时开销下守住了内存安全.
  5. 运行时事件闭环( 执行器与反应器 ): 执行器从就绪队列取出任务并调用 poll poll ;叶子 Future Future 遇到 WouldBlock WouldBlock 时向反应器注册 Waker Waker 并返回 Pending Pending ;操作系统通过 epoll epoll / kqueue kqueue / IOCP IOCP 通知反应器事件就绪后,反应器调用 Waker::wake() Waker::wake() 将任务重新排入执行器队列.

我们可以把从“写下一行 async fn async fn ”到“在操作系统线程上跑完一次非阻塞 I/O”的全链路浓缩为下面这张全景图:

1 术语对照

文中出现的英文术语与中文译名,同样收录于全站 术语对照 中:

异步编程
asynchronous programming
绿色线程
green thread
有栈协程
stackful coroutine
无栈协程
stackless coroutine
分段栈
segmented stack
栈拷贝
stack copying
协作式调度
cooperative scheduling
抢占式调度
preemptive scheduling
半协作式取消
semi-cooperative cancellation
取消安全性
cancellation safety
拉取模型
pull-based model
推送模型
push-based model
语域
register
挂起点
suspension point
状态机
state machine
轮询
poll
唤醒器
waker
伪唤醒
spurious wakeup
自引用结构
self-referential struct
地址固定
pinning
固定类型状态
pinned typestate
析构保证
drop guarantee
结构化固定投影
structural pin projection
执行器
executor
反应器
reactor
2 延伸阅读

关于 Rust 异步机制的设计历史、标准库规范与工程实践,可进一步查阅以下资料: