Async-await 稳定版 Rust 已就绪!

2019 年 11 月 7 日 · Niko Matsakis

本周四,11 月 7 日,async-await 语法作为 1.39.0 版本的一部分正式进入 Rust 稳定版。这项工作已经开发了很长时间——例如,零成本 future 的核心想法,由 Aaron Turon 和 Alex Crichton 于 2016 年首次提出!——我们对最终结果感到非常自豪。我们相信 Async I/O 将成为 Rust 发展历程中越来越重要的一部分。

虽然“async-await”的首次发布是一个具有里程碑意义的事件,但这仅仅是个开始。当前对 async-await 的支持标志着一个“最小可用产品Minimum Viable Product”(MVP)的完成。我们预计还需要一段时间进行完善、改进和扩展。

async-await 进入 Beta 版以来,我们已经取得了很大进展,包括进行了一些关键的诊断改进,这使得 async-await 的错误更易于处理。要参与这项工作,请查看异步基础工作组;如果您无法直接参与,也可以通过提交关于完善问题的 bug 报告,或者提名那些最让您困扰的 bug 来帮助我们,以便指导我们的工作。

async-await 得以实现,离不开许多人的努力。如果没有 cramertj 和 withoutboats 的领导,来自编译器端的实现和完善工作(davidtwco, tmandry, gilescope, csmoe),future 依赖的核心生成器支持(Zoxc),以及 FuturePin API 的基础工作(aturon, alexcrichton, RalfJ, pythonesque),async-await 的实现和设计将无从谈起。当然,还有无数社区成员在 RFC 讨论和讨论中提供的宝贵意见。

异步生态系统中的重大进展

随着 async-await 即将稳定,所有主要的 Async I/O 运行时都在努力添加和扩展对新语法的支持。

Async-await:快速入门

(本节和下一节转载自“Async-await 进入 Beta 版!”一文。)

那么,什么是 async-await?Async-await 是一种编写函数的方式,这些函数可以“暂停”,将控制权返回给运行时,然后在中断处继续执行。通常这些暂停是为了等待 I/O,但也可以有多种其他用途。

您可能熟悉 JavaScript 或 C# 中的 async-await。Rust 的此功能版本类似,但也有一些关键差异。

要使用 async-await,您只需将 fn 改为 async 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 的另一个区别是,它们基于“轮询(poll)”模型,这使得它们零成本。在其他语言中,调用一个 async 函数会立即创建一个 future 并安排其执行:等待 future 并不是执行它的必要条件。但这对于创建的每个 future 都会带来一些开销。

相比之下,在 Rust 中,调用一个 async 函数本身并不会进行任何调度,这意味着我们可以组合复杂的 future 嵌套,而不会产生每个 future 的额外开销。然而,作为最终用户,您会注意到的主要一点是 futures 感觉“惰性”:它们在您对它们进行 await 之前什么也不会做。

如果您想更深入地了解 futures 的底层工作原理,可以查看异步编程圣经(async book)执行器(executor)章节,或者观看 withoutboatsRust LATAM 2019 大会上关于此主题的精彩演讲

总结

我们相信,async-await 在 Rust 稳定版中的可用性将极大地推动 Rust 中的许多新的和令人兴奋的开发。如果您过去尝试过 Rust 中的 Async I/O 并遇到问题——特别是如果您尝试过过去基于组合子的 futures——您会发现 async-await 与 Rust 的借用系统结合得更好。此外,生态系统中现有许多出色的运行时和其他库可供使用。所以,赶紧行动起来,构建项目吧!