探讨future的不同写法。以及其中的差异。
自定义实现一个 trait 特征。需要实现 poll
方法。该方法返回一个枚举值: Poll<T>
, Ready 代表完成包裹了真正的返回数据;Pending 意味着任务还未完成。
pub trait Future {
/// The type of value produced on completion.
#[stable(feature = "futures_api", since = "1.36.0")]
type Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
}
pub enum Poll<T> {
/// Represents that a value is immediately ready.
#[stable(feature = "futures_api", since = "1.36.0")]
Ready(#[stable(feature = "futures_api", since = "1.36.0")] T),
/// Represents that a value is not ready yet.
///
/// When a function returns `Pending`, the function *must* also
/// ensure that the current task is scheduled to be awoken when
/// progress can be made.
#[stable(feature = "futures_api", since = "1.36.0")]
Pending,
}
Executor 会来调用 Future
的 poll
方法根据返回值的不同,决定下一步的动作。
显式返回一个future trait。
fn my_fut() -> impl Future<Output = ()> {
future::ready(())
}
代码示例如下:
async fn ss() -> u32 {
0
}
async 关键字,将函数的原型修改为返回一个future trait。然后将执行的结果包装在一个新的future中返回。大致相当于:
fn ss() -> impl Future<Output = u32> {
async { 0 }
}
从这里可以看到,async fn 永远是返回 Ready(T),而没有办法返回 Pending的。
async
代码块实现了一个匿名的 Future Trait,名为GenFuture,实现了 Future,并包裹一个 generator。如下所示:
pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
where
T: Generator<ResumeTy, Yield = ()>,
{
struct GenFuture<T: Generator<ResumeTy, Yield = ()>>(T);
// We rely on the fact that async/await futures are immovable in order to create
// self-referential borrows in the underlying generator.
impl<T: Generator<ResumeTy, Yield = ()>> !Unpin for GenFuture<T> {}
impl<T: Generator<ResumeTy, Yield = ()>> Future for GenFuture<T> {
type Output = T::Return;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
// Safety: Safe because we're !Unpin + !Drop, and this is just a field projection.
let gen = unsafe { Pin::map_unchecked_mut(self, |s| &mut s.0) };
// Resume the generator, turning the `&mut Context` into a `NonNull` raw pointer. The
// `.await` lowering will safely cast that back to a `&mut Context`.
match gen.resume(ResumeTy(NonNull::from(cx).cast::<Context<'static>>())) {
GeneratorState::Yielded(()) => Poll::Pending,
GeneratorState::Complete(x) => Poll::Ready(x),
}
}
}
GenFuture(gen)
}
GenFuture 是一个实现了 Future 的 generator。因此在 Executor 执行这样的 Future 会进入相应的 poll 方法,接下来 gen.resume 将会驱动 generator执行 async {} 的内容。如果 async {} 暂时无法完成,则返回 Yielded
,进而 gen.resume 返回 Poll::Pending
,暂停执行。一旦恢复执行,generator 返回 Complete
,gen.resume 返回Poll::Ready(x)
,Future 任务完成。
此外,如果 async {} 执行中嵌套进入了下一级的 async{},则递进执行下一级 generator。
每一个await本身就像一个小型的执行器,在循环中查询任务的状态。
await 执行 generator 本身 async {} 代码。大致的逻辑就是循环调用Future的 poll 方法。如果返回 Pending,则 yield,否则退出循环,结束 Future。
示意代码如下:
loop {
match polling_future_block() {
Pending => yield,
Ready(x) => break
}
}