重大消息!截至撰写本文时,**Rust Beta 通道已提供 async-await 的语法支持!** 它将在预计于 **2019 年 11 月 7 日** 发布的 1.39 版本中提供。一旦 async-await 进入稳定版,这将标志着 **为 Rust 启用高效且符合人体工程学原理的异步 I/O 的多年努力的顶峰**。然而,这并不意味着道路的终点:在抛光方面(我们今天得到的一些错误消息,嗯,不太好)和功能集方面(特质中的 async fn,有人吗?)还有更多工作要做。
(如果您不熟悉 async-await 是什么,不要绝望!本文后面将介绍入门知识和其他细节!)
生态系统中 async-await 支持快速增长
但 async-await 从来就不是全部故事。要充分利用 async-await,您还需要强大的库和充满活力的生态系统。**幸运的是,您有很多不错的选择,而且它们还在不断改进:**
- 例如,异步运行时 tokio 最近宣布了基于 async-await 的 alpha 版本;
- 最近宣布的 async-std 库从一开始就基于新的 async-await 语法构建;
- 使用 wasm-bindgen-futures,您甚至可以将 Rust Futures 与 JavaScript promises 桥接;
- hyper 库 已 迁移 以采用标准 Rust futures;
- futures-rs 库 的 0.3.0 版本将支持 async-await,并将与 async-await 进入稳定版时同时发布(您现在可以使用 0.3.0-alpha 版本);
- 最后,async-await 支持也开始在更高级的 Web 框架 中提供。
重构 Rust 组织中的异步 I/O
现在 async-await 即将进入稳定版,我们正在利用这个机会对 Rust 团队结构进行一些调整。当前结构包括两个工作组:异步基础工作组,专注于构建核心语言支持,以及 异步生态系统工作组,专注于支持生态系统发展。
**然而,鉴于生态系统中所有正在进行的活动,对 异步生态系统工作组 的需求并不那么大,因此我们决定将其解散。** 我们将弃用 rustasync github 组织。 areweasyncyet.rs 和 arewewebyet.org 网站将迁移到主 rust-lang 组织,但其他项目的命运将由构建它们的人决定。一些项目可能会被弃用,其余项目将独立维护。
**同时,异步基础工作组 将继续存在,但重点将有所转变。** 现在 async-await 正在走向稳定,重点将放在抛光上,例如改进诊断、修复较小的错误,以及改进文档,例如 异步书籍。一旦在这方面取得进展,我们将考虑接下来要实现哪些功能。
(旁注:这是我们第一次选择解散工作组,我们意识到我们没有为此制定正式的政策。我们已 创建了一个问题,与 治理工作组 协商未来如何处理此类情况。)
Async await:快速入门
那么,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 与其他语言中的 futures 之间的另一个区别是,它们基于“轮询”模型,这使得它们 **零成本**。在其他语言中,调用异步函数会立即创建一个 future 并将其安排执行:等待 future 实际上并不需要它执行。但这意味着为创建的每个 future 都会产生一些开销。
相反,在 Rust 中,调用异步函数本身不会进行任何调度,这意味着我们可以组合一个复杂的 future 嵌套,而不会产生每个 future 的成本。但是,作为最终用户,您会注意到的一点是 **futures 感觉“懒惰”**:它们在您等待它们之前不会执行任何操作。
如果您想更深入地了解 futures 在幕后是如何工作的,请查看 异步书籍的 executor 部分,或观看 withoutboats 在 Rust LATAM 2019 上关于此主题的 精彩演讲。
总结
总之,如果您有兴趣在 Rust 中使用异步 I/O,现在是一个非常激动人心的时刻!随着 async-await 语法在 11 月进入稳定版,编写 futures 将比以往任何时候都更容易(特别是如果您过去尝试过使用基于组合器的 futures,您会发现 async-await 与 Rust 的借用系统更好地集成)。此外,生态系统中现在已经提供了一些很棒的运行时和其他库来使用。所以,开始动手构建吧!
(哦,对了,如果您遇到令人困惑或意外的问题,请提交错误报告,以便我们改进用户体验!)