Rust async and await
async/await
最近编写了一些 Rust 代码,平时也是一直使用 async/await 没怎么思考过后面到底是什么,然后在某天洗澡的时候还是睡觉前的时候,突然想起了这个东西。
网上各种解释文章基本会讲到当一个函数使用 async 修饰一个返回类型为 T 的函数的时候,其实函数会返回一个 impl std:future:Future<T>。
我以前编写 Java 代码惯性思维很容易将 trait 和 interface 做比较,然后就类比为返回一个对象,这个对象实现了某个接口,这种一笔带过的思考方式。
但是问题就是出现在这里,不管 Java 还是 Rust 还是 C/C++ 之类的编程语言,函数返回类型都是确定的,不管是基础类型还是高级类型还是指针,这个类型大小确定。
但是当我们说 Rust 一个异步函数会返回一个 impl std:future:Future<T> 的时候,我们到底在说什么,啥?返回的是什么东西?
答案:一个无中生有的类型。
编译器编译的时候,会将异步函数内部涉及到栈上变量还有这种 .await 调用的状态封装成为一个匿名结构体。
再后面的内容我就不知道了。
Pin<Box>
- 异步函数的状态里面的变量可能出现引用,所以不能移动,所以需要移动到堆上。
Pin是一个在编译期间生效,在运行期间给抹除掉的魔法。Pin所做的事情只有一件事,就是所以!Unpin的对象Pin了之后就无法再次恢复到原本的样子。
Drop Guard
这个也是最近开发的时候遇到的一个问题,在异步函数因为 io 挂起的时候,这个时候对这个 Future 执行 abort 操作的时候,并不是触发 io error,而是直接把这个异步函数对应的状态帧丢弃掉,就是说在某个.await 那一行直接停止了。没有任何后续的执行流程,后续的成功、错误检测都不会触发。
这个时候,我会创建一个匿名的数据类型,并且实现 Drop 特征,做一个作用域结束之后的资源回收,类似 Go 的 defer。感谢 Rust 的生命周期系统,这个 Drop 特征一定是我会用这个编程语言前三个理由之一。
目前 std 也开始添加这个DropGuard功能了,估计两个版本下来就能稳定吧。