陈天 · Rust 编程第一课
陈天
Tubi TV 研发副总裁
23195 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 65 讲
基础篇 (21讲)
陈天 · Rust 编程第一课
15
15
1.0x
00:00/00:00
登录|注册

39|异步处理:async/await内部是怎么实现的?

drop
wake_by_ref
wake
clone
_marker
name_ptr
name
resume(self: Pin<&mut Self>, arg: R) -> GeneratorState<Self::Yield, Self::Return>
Return
Yield
RawWakerVTable
Box
SelfReference
PhantomPinned
Generator
wake()
pointer
Waker
poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>
Output
思考题
自引用结构
Unpin
GenFuture
Waker
Pin
Context
Future
异步处理:async/await内部是怎么实现的?

该思维导图由 AI 生成,仅供参考

你好,我是陈天。
学完上一讲,我们对 Future 和 async/await 的基本概念有一个比较扎实的理解了,知道在什么情况下该使用 Future、什么情况下该使用 Thread,以及 executor 和 reactor 是怎么联动最终让 Future 得到了一个结果。
然而,我们并不清楚为什么 async fn 或者 async block 就能够产生 Future,也并不明白 Future 是怎么被 executor 处理的。今天我们就继续深入下去,看看 async/await 这两个关键词究竟施了什么样的魔法,能够让一切如此简单又如此自然地运转起来。
提前说明一下,我们会继续围绕着 Future 这个简约却又并不简单的接口,来探讨一些原理性的东西,主要是 Context 和 Pin 这两个结构:
pub trait Future {
type Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
}
这堂课的内容即便没有完全弄懂,也并不影响你使用 async/await。如果精力有限,你可以不用理解所有细节,只要抓住这些问题产生的原因,以及解决方案的思路即可。

Waker 的调用机制

确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

异步处理在编程中扮演着重要角色,而async/await是一种常见的异步处理方式。本文深入探讨了async/await的内部实现原理,重点围绕Future接口、Context和Pin结构展开讨论。文章指出Rust标准库并不提供异步运行时,只规定了基本接口,具体实现由第三方异步运行时库决定。接着,文章详细解释了async函数内部生成的代码,以及如何将其转化为Future的实现,展示了其实际状态机的迁移过程。最后,文章指出这些看似简单的异步处理背后隐藏了一套复杂的状态机管理代码,进而引出了Pin的必要性。Pin的出现对解决自引用结构带来的潜在危害至关重要。通过对async/await内部实现原理的深入剖析,读者能够更好地理解其工作机制,为进一步深入学习提供了基础。文章还介绍了Unpin和PhantomPinned的作用,以及async产生的Future类型。最后,通过对Future接口各个部分的深入探讨,读者能够对async/await的实现原理有一个完整的认识。整体而言,本文通过深入剖析async/await的内部实现原理,为读者呈现了异步处理背后的复杂性,以及Pin和Unpin在异步处理中的重要性。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《陈天 · Rust 编程第一课》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(13)

  • 最新
  • 精选
  • GengTeng
    我之前记录并翻译过无船同志(withoutboats)的一个讲座,供大家参考:https://gteng.org/2021/01/30/zero-cost-async-io/

    作者回复: 👍

    2021-11-30
    2
    8
  • 罗同学
    Pin了后的数据 所有者变成谁了?

    作者回复: 所有者还是之前的变量,只不过一般会把它 shadow 掉,这样没有人可以拿到。当这个变量离开作用域时还是会被回收。 ```rust use std::pin::Pin; fn main() { let s = "hello".to_string(); println!("addr of s(stack): {:p}", &s); let s = Pin::new(s); println!("addr of pinned s: {:p}", &s); } ```

    2021-11-29
    3
  • dva
    Box<T>是Unpin,因为Box<T>实现了Unpin trait

    作者回复: 👍

    2021-12-18
    1
  • wowotuo
    讲得很牛逼,现在反反复复听了看了不下10次

    作者回复: 👍

    2022-01-12
  • 良师益友
    以前在这里卡住了,这次说明白了,感谢老师

    作者回复: 👍

    2021-11-29
  • 清风徐来
    有了Pin为啥还有!UnPin
    2022-02-22
    2
    1
  • Rustlab
    我越看越困惑, write_hello_file_async("/tmp/hello").await?;这里,如果只是生成loop,那这就是同步代码了,能详细讲一讲, write_hello_file_async("/tmp/hello").await?;在调用处是如何被处理,其如何注册到异步运行时、最后future的poll方法是怎么样被不断重复调用的吗?这里的poll里面有一个loop,我感觉真实场景不会这么干吧。
    2023-03-15归属地:湖南
  • Rustlab
    我越看越困惑, write_hello_file_async("/tmp/hello").await?;这里,如果只是生成loop,那这就是同步代码了,能详细讲一讲, write_hello_file_async("/tmp/hello").await?;在调用处是如何被处理,其如何注册到异步运行时、最后future的poll方法是怎么样被不断重复调用的吗?这里的poll里面有一个loop,我感觉真实场景不会这么干吧。
    2023-03-15归属地:湖南
  • 约书亚
    有些凌乱,在第二个move_creates_issue示例(使用了Pin的那个)里,move_it无法调用是因为原来的SelfReference类型的data(值)被shadow了,如果把data改个名字,move_it依旧可以调用,和Pin没啥关系? 不过如果将move_it与它上面的那条语句互换下位置,确实会编译不通过,原因是在有借用的情况下移动,那这么说我不使用Pin,随便使用一个&SelfReference或者&mut SelfReference,也能阻止移动呢?
    2022-11-23归属地:天津
    3
  • doubled
    老师能具体讲讲phantomdata么,在Waker中为什么marker要是phantomdata<fn(&'a ())->&'a ()>,能不能使用phantomdata<&'a ()>或者使用phantomdata<&'a mut ()>
    2022-11-13归属地:福建
收起评论
显示
设置
留言
13
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部