Rust 稳定版上的 Async-await!

2019 年 11 月 7 日 · Niko Matsakis

在即将到来的 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),如果没有对 FuturePin API 的基础工作(aturon、alexcrichton、RalfJ、pythonesque),当然,如果没有来自社区成员在 RFC 线程和讨论中的大量输入,实现和设计将永远不会实现。

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

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

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 在幕后是如何工作的,请查看 异步书籍 中的 执行器部分,或者观看 精彩的演讲,该演讲由 withoutboatsRust LATAM 2019 上发表,主题是关于这个问题的。

总结

我们相信,在 Rust 稳定版上拥有 async-await 将成为 Rust 中许多新兴和令人兴奋的发展的关键推动因素。如果你过去尝试过 Rust 中的异步 I/O 并遇到过问题——特别是如果你尝试过过去基于组合器的 futures——你会发现 async-await 与 Rust 的借用系统更好地集成。此外,现在生态系统中已经有了许多很棒的运行时和其他库可供使用。所以,去构建吧!