本周四,11 月 7 日,async-await 语法作为 1.39.0 版本的一部分正式进入 Rust 稳定版。这项工作已经开发了很长时间——例如,零成本 future 的核心想法,由 Aaron Turon 和 Alex Crichton 于 2016 年首次提出!——我们对最终结果感到非常自豪。我们相信 Async I/O 将成为 Rust 发展历程中越来越重要的一部分。
虽然“async-await”的首次发布是一个具有里程碑意义的事件,但这仅仅是个开始。当前对 async-await 的支持标志着一个“最小可用产品”(MVP)的完成。我们预计还需要一段时间进行完善、改进和扩展。
自async-await 进入 Beta 版以来,我们已经取得了很大进展,包括进行了一些关键的诊断改进,这使得 async-await 的错误更易于处理。要参与这项工作,请查看异步基础工作组;如果您无法直接参与,也可以通过提交关于完善问题的 bug 报告,或者提名那些最让您困扰的 bug 来帮助我们,以便指导我们的工作。
async-await 得以实现,离不开许多人的努力。如果没有 cramertj 和 withoutboats 的领导,来自编译器端的实现和完善工作(davidtwco, tmandry, gilescope, csmoe),future 依赖的核心生成器支持(Zoxc),以及 Future
和 Pin
API 的基础工作(aturon, alexcrichton, RalfJ, pythonesque),async-await 的实现和设计将无从谈起。当然,还有无数社区成员在 RFC 讨论和讨论中提供的宝贵意见。
异步生态系统中的重大进展
随着 async-await 即将稳定,所有主要的 Async 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,您只需将 fn
改为 async fn
即可。
async
与普通函数不同,调用 async fn
并不会立即产生任何效果。相反,它返回一个 Future
。这是一个暂停的计算任务,正等待执行。要实际执行这个 future,请使用 .await
运算符。
async
这个例子展示了 Rust 与其他语言的第一个区别:我们使用 future.await
而不是 await future
。这种语法与 Rust 用于传播错误的 ?
运算符更好地集成(毕竟,错误在 I/O 中非常常见)。您可以简单地写 future.await?
来等待 future 的结果并传播错误。它还有一个优势是可以使方法链调用变得轻松。
零成本 futures
Rust futures 与 JS 和 C# 中 futures 的另一个区别是,它们基于“轮询(poll)”模型,这使得它们零成本。在其他语言中,调用一个 async 函数会立即创建一个 future 并安排其执行:等待 future 并不是执行它的必要条件。但这对于创建的每个 future 都会带来一些开销。
相比之下,在 Rust 中,调用一个 async 函数本身并不会进行任何调度,这意味着我们可以组合复杂的 future 嵌套,而不会产生每个 future 的额外开销。然而,作为最终用户,您会注意到的主要一点是 futures 感觉“惰性”:它们在您对它们进行 await 之前什么也不会做。
如果您想更深入地了解 futures 的底层工作原理,可以查看异步编程圣经(async book)的执行器(executor)章节,或者观看 withoutboats 在 Rust LATAM 2019 大会上关于此主题的精彩演讲。
总结
我们相信,async-await 在 Rust 稳定版中的可用性将极大地推动 Rust 中的许多新的和令人兴奋的开发。如果您过去尝试过 Rust 中的 Async I/O 并遇到问题——特别是如果您尝试过过去基于组合子的 futures——您会发现 async-await 与 Rust 的借用系统结合得更好。此外,生态系统中现有许多出色的运行时和其他库可供使用。所以,赶紧行动起来,构建项目吧!