Waker 是异步 Rust 里最底层、最容易被忽略的一环:Future 返回 Pending 之后,靠它才能被再次 poll。这篇用自己写的 vtable 把 Waker 的四个操作逐个计数,再演示「忘了 wake」这个无声的挂起。
编译:成功
运行(退出码 0):
size_of::<Waker>() = 16 字节(两个指针:数据指针 + vtable 指针)
创建后: clone 0 / wake 0 / wake_by_ref 0 / drop 0
w.clone(): clone 1 / wake 0 / wake_by_ref 0 / drop 0
w2.wake_by_ref(): clone 1 / wake 0 / wake_by_ref 1 / drop 0(不消耗 w2)
w2.wake(): clone 1 / wake 1 / wake_by_ref 1 / drop 0(wake 消耗 w2,所以没有 drop 调用:由 wake 的实现负责释放)
drop(w): clone 1 / wake 1 / wake_by_ref 1 / drop 1手写执行器里 Waker 的用法见Async Runtime 做了什么。
编译:成功
运行(退出码 0):
poll #1:Pending,保存了 waker(clone 1 / wake 0 / wake_by_ref 0 / drop 0)
(外部事件调用 saved.wake())
poll #2:Pending,保存了 waker(clone 2 / wake 1 / wake_by_ref 0 / drop 0)
(外部事件调用 saved.wake())
poll #3:Ready
结束:clone 2 / wake 2 / wake_by_ref 0 / drop 0 编译:成功
运行(退出码 0):
a.will_wake(&b)(b 是 a 的克隆): true
a.will_wake(&c)(同一个数据指针 + 同一张 vtable,另一个实例): true
Waker::noop().will_wake(&Waker::noop()): true
a.will_wake(Waker::noop()): false 编译:成功
运行(退出码 0):
注册并调用了 waker:Some(("就绪", 2))
条件满足了但没调用 waker:None(500 ms 后放弃:任务永远睡下去)手写完整 Future 见自定义 Future。