在即将到来的 11 月 7 日星期四,async-await 语法将作为 1.39.0 版本的一部分,正式进入 Rust 稳定版。这项工作已经开发了很长时间——例如,零成本 futures 的关键理念是在 2016 年由 Aaron Turon 和 Alex Crichton 首次提出!——我们对最终结果感到非常自豪。我们相信异步 I/O 将成为 Rust 故事中越来越重要的一部分。
虽然这个“async-await”的第一个版本是一个重大的事件,但它也仅仅是开始。当前对 async-await 的支持标志着一种“最小可行产品”(MVP)。我们预计在一段时间内会对其进行完善、改进和扩展。
自从 async-await 进入 beta 版以来,我们已经取得了很大的进展,包括进行了一些 关键的诊断改进,这些改进有助于使 async-await 错误更容易理解。要参与这项工作,请查看 异步基础工作组;如果你没有其他事情可做,你可以通过提交关于完善问题的错误报告或 提名那些最困扰你的错误来帮助我们,以帮助我们确定工作方向。
对那些让 async-await 成为现实的人们表示衷心的感谢。如果没有 cramertj 和 withoutboats 的领导,如果没有编译器方面的实现和完善工作(davidtwco、tmandry、gilescope、csmoe),如果没有 futures 构建的基础生成器支持(Zoxc),如果没有对 Future
和 Pin
API 的基础工作(aturon、alexcrichton、RalfJ、pythonesque),当然,如果没有来自社区成员在 RFC 线程和讨论中的大量输入,实现和设计将永远不会实现。
异步生态系统中的重大发展
现在 async-await 即将稳定,所有主要的异步 I/O 运行时都在努力添加和扩展对新语法的支持
- tokio 运行时 最近宣布了一系列调度程序改进,他们计划在 11 月发布一个支持 async-await 语法的稳定版本;
- async-std 运行时 在过去几个月里一直在发布每周版本,并计划在 async-await 进入稳定版后不久发布他们的 1.0 版本;
- 使用 wasm-bindgen-futures,你甚至可以将 Rust Futures 与 JavaScript promises 桥接;
- hyper 库 已 迁移以采用标准的 Rust futures;
- 新发布的 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 的结果并传播错误。它还有助于使方法链变得轻松。
零成本 futures
Rust futures 与 JS 和 C# 中的 futures 之间的另一个区别是它们基于“轮询”模型,这使得它们零成本。在其他语言中,调用异步函数会立即创建一个 future 并将其安排执行:等待 future 对于其执行来说不是必需的。但这意味着每个创建的 future 都会产生一些开销。
相反,在 Rust 中,调用异步函数本身不会进行任何调度,这意味着我们可以组合一个复杂的 future 嵌套,而不会产生每个 future 的成本。但是,作为最终用户,你主要会注意到的是futures 感觉“懒惰”:它们在你等待它们之前不会做任何事情。
如果你想更深入地了解 futures 在幕后是如何工作的,请查看 异步书籍 中的 执行器部分,或者观看 精彩的演讲,该演讲由 withoutboats 在 Rust LATAM 2019 上发表,主题是关于这个问题的。
总结
我们相信,在 Rust 稳定版上拥有 async-await 将成为 Rust 中许多新兴和令人兴奋的发展的关键推动因素。如果你过去尝试过 Rust 中的异步 I/O 并遇到过问题——特别是如果你尝试过过去基于组合器的 futures——你会发现 async-await 与 Rust 的借用系统更好地集成。此外,现在生态系统中已经有了许多很棒的运行时和其他库可供使用。所以,去构建吧!