在即将到来的 11 月 7 日星期四,async-await 语法将作为 1.39.0 版本的一部分在稳定版 Rust 中发布。 这项工作已经开发了很长时间——例如,零成本 future 的关键思想是 Aaron Turon 和 Alex Crichton 在 2016 年首次提出的!——我们为最终结果感到非常自豪。我们认为,异步 I/O 将成为 Rust 发展中越来越重要的一部分。
虽然首次发布 “async-await” 是一件意义重大的事情,但也仅仅是个开始。目前对 async-await 的支持标志着一种 “最小可行产品”(MVP)。我们期望在一段时间内对其进行润色、改进和扩展。
自从 async-await 进入 beta 版 以来,我们已经取得了很大的进展,包括进行了一些 关键的诊断改进,这些改进有助于使 async-await 错误更容易理解。要参与这项工作,请查看 Async 基础工作组;即使不能直接参与,你也可以通过提交关于润色问题的错误,或 提名那些最困扰你的错误 来帮助我们,以指导我们的工作。
非常感谢那些使 async-await 成为现实的人。如果没有 cramertj 和 withoutboats 的领导,以及编译器方面的实施和润色工作(davidtwco、tmandry、gilescope、csmoe),以及 future 构建的核心生成器支持(Zoxc),以及在 Future
和 Pin
API 上的基础工作(aturon、alexcrichton、RalfJ、pythonesque),当然还有众多社区成员在 RFC 线程和讨论中提供的意见,async-await 的实现和设计永远不会发生。
异步生态系统中的重大发展
现在,随着 async-await 接近稳定,所有主要的异步 I/O 运行时都在努力添加和扩展对新语法的支持
- tokio 运行时 最近宣布了一些调度器改进,他们计划在 11 月发布一个支持 async-await 语法的稳定版本;
- async-std 运行时 在过去几个月里每周都会发布版本,并计划在 async-await 稳定后不久发布 1.0 版本;
- 使用 wasm-bindgen-futures,你甚至可以将 Rust Future 与 JavaScript promise 连接起来;
- hyper 库 已经 迁移 以采用标准的 Rust future;
- 新发布的 futures-rs 库 的 0.3.0 版本包括对 async-await 的支持;
- 最后,async-await 的支持也开始在更高级别的 Web 框架 以及其他有趣的应用程序中可用,例如
futures_intrusive
crate。
Async-await:快速入门
(本节和下一节摘自 “Async-await 进入 beta 版!” 一文。)
那么,什么是 async-await?Async-await 是一种编写可以“暂停”、将控制权返回给运行时,然后从暂停的地方继续执行的函数的方式。通常,这些暂停是为了等待 I/O,但也可以有许多其他用途。
你可能熟悉 JavaScript 或 C# 中的 async-await。Rust 的这个特性版本类似,但有一些关键区别。
要使用 async-await,你需要先编写 async fn
而不是 fn
async fn first_function() -> u32 { .. }
与普通函数不同,调用 async fn
不会立即产生任何效果。相反,它会返回一个 Future
。这是一个等待执行的挂起计算。要实际执行 future,请使用 .await
操作符
async fn another_function() {
// Create the future:
let future = first_function();
// Await the future, which will execute it (and suspend
// this function if we encounter a need to wait for I/O):
let result: u32 = future.await;
...
}
这个例子显示了 Rust 与其他语言的第一个区别:我们写 future.await
而不是 await future
。此语法与 Rust 的 ?
操作符更好地集成在一起,用于传播错误(毕竟,这在 I/O 中非常常见)。你可以简单地写 future.await?
来等待 future 的结果并传播错误。它还具有使方法链变得轻松的优点。
零成本 future
Rust future 与 JS 和 C# 中 future 的另一个区别是,它们基于“轮询”模型,这使得它们是零成本的。在其他语言中,调用异步函数会立即创建一个 future 并将其安排为执行:等待 future 对于它的执行不是必需的。但是,这意味着创建的每个 future 都会产生一些开销。
相比之下,在 Rust 中,调用异步函数本身不会进行任何调度,这意味着我们可以组合一个复杂的 future 嵌套,而不会产生每个 future 的成本。但是,作为最终用户,你会注意到的主要事情是 future 感觉 “懒惰”:它们在等待它们之前不做任何事情。
如果你想更深入地了解 future 在底层是如何工作的,请查看 异步书籍的执行器部分,或观看 withoutboats 在 Rust LATAM 2019 上就此主题所做的 精彩演讲。
总结
我们相信在稳定版 Rust 上使用 async-await 将成为 Rust 中许多新的和令人兴奋的发展的关键推动力。如果你过去在 Rust 中尝试过异步 I/O 并且遇到过问题——特别是如果你尝试过基于组合器的旧 future——你会发现 async-await 与 Rust 的借用系统更好地集成在一起。此外,现在生态系统中提供了许多出色的运行时和其他库可供使用。所以,赶紧去构建东西吧!