伍佰目录 短网址
  当前位置:海洋目录网 » 站长资讯 » 站长资讯 » 文章详细 订阅RssFeed

【投稿】刀哥:Rust学习笔记 4

来源:本站原创 浏览:186次 时间:2021-07-21
@[TOC](Rust 学习心得<4>:async/await 如何工作)

2019年底Rust正式支持 async/await语法,完成了Rust协程的最后一块拼图,从而异步代码可以用一种类似于Go的简洁方式来书写。然而对于程序员来讲,还是很有必要理解async/await的实现原理。

async

简单地说,async语法生成一个实现 Future 对象。如下async函数:

async fn foo() -> {
...
}

async关键字,将函数的原型修改为返回一个Future trait object。然后将执行的结果包装在一个新的future中返回,大致相当于:

fn foo() -> impl Future<Output = ()> {
   async { ... }
}

更重要的是async 代码块会实现一个匿名的 Future trait object ,包裹一个 Generator。也就是一个实现了 Future 的 GeneratorGenerator实际上是一个状态机,配合.await当每次async 代码块中任何返回 Poll::Pending则即调用generator yeild,让出执行权,一旦恢复执行,generator resume 继续执行剩余流程。以下是这个状态机Future的代码:

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);
   
   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> {
           let gen = unsafe { Pin::map_unchecked_mut(self, |s| &mut s.0) };

           match gen.resume(ResumeTy(NonNull::from(cx).cast::<Context<'static>>())) {
               GeneratorState::Yielded(()) => Poll::Pending,  // 当代码无法继续执行,让出控制权,返回 Pending,等待唤醒
               GeneratorState::Complete(x) => Poll::Ready(x), // 执行完毕
           }
       }
   }
   GenFuture(gen)
}

可以看到这个特别的Future是通过Generator来运行的。每一次gen.resume()会顺序执行async block中代码直到遇到yieldasync block中的.await语句在无法立即完成时会调用yield交出控制权等待下一次resume。而当所有代码执行完,也就是状态机进入Completeasync block返回Poll::Ready,代表Future执行完毕。

await

每一个await本身就像一个执行器,在循环中查询Future的状态。如果返回Pending,则 yield,否则退出循环,结束当前Future。代码逻辑大致如下:

loop {
match some_future.poll() {
Pending => yi��ֱ��׳,��������eld,
Ready(x) => break
}
}

为了更好地理解async/await的原理,我们来看一个简单例子:

async fn foo() {
do_something_1();
some_future.await;
do_something_2();
}

使用async修饰的异步函数foo被改写为一个Generator状态机驱动的Future,其内部有一个some_future.await,中间穿插do_something_x()等其他操作。当执行foo().await时,首先完成do_something_1(),然后执行some_future.await,若some_future返回Pending,这个Pending被转换为yield,因此顶层foo()暂时也返回Pending,待下次唤醒后,foo()调用resume()继续轮询some_future,若some_future返回Ready,表示some_future.await完毕,则foo()开始执行do_something_2()。这里的关键点在于,因为状态机的控制,所以当foo()再次被唤醒时,不会重复执行do_something_1(),而是会从上次yield的的地方继续执行some_future.await,相当于完成了一次任务切换,这也是无栈协程的工作方式。

总结

async/await 通过一个状态机来控制代码的流程,配合Executor完成协程的切换。在此之后,书写异步代码不需要手动写Future及其poll方法,特别是异步逻辑的状态机也是由async自动生成,大大简化程序员的工作。虽然async/await出现的时间不长,目前纯粹使用async/await书写的代码还不是主流,但可以乐观地期待,今后更多的项目会使用这个新语法。


  推荐站点

  • At-lib分类目录At-lib分类目录

    At-lib网站分类目录汇集全国所有高质量网站,是中国权威的中文网站分类目录,给站长提供免费网址目录提交收录和推荐最新最全的优秀网站大全是名站导航之家

    www.at-lib.cn
  • 中国链接目录中国链接目录

    中国链接目录简称链接目录,是收录优秀网站和淘宝网店的网站分类目录,为您提供优质的网址导航服务,也是网店进行收录推广,站长免费推广网站、加快百度收录、增加友情链接和网站外链的平台。

    www.cnlink.org
  • 35目录网35目录网

    35目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向35目录推荐、提交优秀网站。

    www.35mulu.com
  • 就要爱网站目录就要爱网站目录

    就要爱网站目录,按主题和类别列出网站。所有提交的网站都经过人工审查,确保质量和无垃圾邮件的结果。

    www.912219.com
  • 伍佰目录伍佰目录

    伍佰网站目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向伍佰目录推荐、提交优秀网站。

    www.wbwb.net