4

【译文】Rust 2024 展望:Async Rust

 8 months ago
source link: https://www.techug.com/post/async-rust-2024/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

每年到了这个时候,人们的思绪就会转向……当然是 “Rust”。我想每年都是这样。今年对于 Rust 来说是非常重要的一年,不过我认为发生的很多事情更像是在 “为 2024 年的成功做准备”。让我们来谈谈 2024 年!我将发表一系列博文,介绍我对 Rust 感到兴奋的不同方面,以及我认为我们应该做的事情。为了把事情具体化,我将用提议目标(基本上就是我认为我们今年可以完成的一项具体工作)来构架 2024。在第一篇文章中,我将重点讨论async Rust。

我们在 2023 年做了什么

12 月 28 日,随着 Rust 1.75.0 的发布,我们稳定了 traits 中的 async fn 和 impl trait。这是一件大事。自 2019 年以来,traits 中的 async fn 就一直被 “认为是硬核“,而它们基本上是我们需要做的一切让 async 变得更好的基础。

对我来说,Async Rust 展示了 Rust 的优点和缺点。它实现了 Rust 关于 “高层代码、底层性能 “的承诺。基于经过高度调整的 Tokio 运行时,Rust 中的network service始终具有更紧凑的尾部延迟和更低的内存使用率,这意味着你可以用更少的资源为更多的客户端提供服务。此外,由于 Rust 没有对运行时进行硬编码,因此您可以编写异步 Rust 代码,用于甚至没有底层操作系统的嵌入式环境,或介于两者之间的任何地方。

然而,用与我交谈过的一位亚马逊工程师的话来说,”Async Rust 就是 Rust on hard mode”,这仍然是事实。要真正缩小这一差距,需要在语言、标准库和生态系统方面下功夫。我们不可能在 2024 年实现所有目标,但我认为我们可以取得长足进步。

目标:在第二季度解决send bound问题

去年,我们在traits 中的异步函数方面取得了很大进展,但我们仍然无法覆盖通用traits 的用例,这些traits 既可以与work-stealing执行器一起使用,也可以不与work-stealing执行器一起使用。一个非常具体的例子就是 Service trait from tower。要处理这种用例,我们需要解决 send bound problem。我们对这个问题有很多想法,甚至已经有了返回类型符号(子集)的原型实现,所以我们已经做好了成功的准备。我认为我们应该争取在第二季度末(基本上是夏天)完成这项工作。这反过来又会解锁 tower crate 的 1.0 版本,让我们拥有一个中间件稳定的trait。

目标:在第三季度稳定异步闭包的 MVP

异步的圣杯是,你应该能够轻松地将任何同步函数变成异步函数。2019 MVP 仅支持顶层函数和固有方法。现在,我们将其扩展到了trait 方法。2024 年,我们将迈出下一步,支持异步闭包。这将允许人们定义迭代器 map 等组合方法,并避免目前所需的复杂变通方法。

对于第一个目标,我认为我们应该努力开发 MVP。最近,Ers 和我勾画了一个我们认为非常可行的 MVP。一开始,我们创建了 AsyncFn trait ,其外观与 Fn trait 层次结构如出一辙…

trait AsyncFnOnce<A> {
    type Output;
    
    async fn call_once(self, args: A) -> Self::Output;
}

trait AsyncFnMut<A>: AsyncFnOnce<A> {
    async fn call_mut(&mut self, args: A) -> Self::Output;
}

trait AsyncFn<A>: AsyncFnMut<A> {
    async fn call(self, args: A) -> Self::Output;
}

…和编写 async || <expr> 等异步闭包的能力,以及一个桥梁使任何返回 future 的函数也能实现适当的 AsyncFn traits。Async clsoures 将阻止我们创建组合特质,就像一个真正漂亮的 async iterators 版本。

本 MVP 并不打算作为最终状态,但打算与我们最终采用的任何最终状态兼容。如何将 AsyncFn traits与常规 Fn traits整合起来,仍然是一个非常有趣的问题。尽管如此,我认为我们可以在探索这个问题的同时稳定上述 MVP。

目标:在第四季度为 “maybe async “编写一个 RFC(或者决定不编写!)。

围绕 async 的一个大问题是,我们是否应该支持以某种方式编写 “maybe  async “代码。这个想法经历了很多名字。Yosh 和 Oli 最初发起了一种名为 “关键字泛型”(keyword generics)的东西,后来又改名为 “效果泛型”(effect generics)。我更喜欢 “trait 转换器”(trait transformers)这一框架,我还写过一篇博文,介绍trait 转换器如何让异步闭包变得更加合适。

有人对这是否是一个好的方向持怀疑态度。关于异步闭包,还有其他思考方式(不过 Errs 指出了一个问题,我希望能在以后的文章中讨论)。Boats 写了很多博文表达担忧,而类型团队的成员也表达了对编写泛型效果代码的担忧。我认为这些担忧很有道理!

总的来说,我仍然相信,像trait 转换器这样的东西可以让 Rust 感觉更简单,并帮助我们扩展以适应未来的需求。但我认为我们必须证明自己的观点!我在 2024 年的目标正是如此。我的想法是撰写一份 RFC,提出一个 “maybe  async”的方案,并让 RFC 被接受。为了消除类型团队的顾虑,我认为需要将 “maybe  async “正式建模为 a-mir-formality 的一部分,以便每个人都能理解它将如何工作。

另一种可能的结果是,我们选择放弃这个想法。也许复杂性真的不可行。或者是语言设计感觉不合适。我对此也没有意见,但无论如何,我认为我们都需要在今年确定一个计划。

扩展目标:稳定生成器语法

作为一个扩展目标,如果能支持生成器表达式(基本上是一种编写异步iterators的方法),那将会非常酷。Errs 最近开启了一项 PR,为异步添加nightly支持,而 RFC #3513 则建议为 Rust 2024 保留 gen 关键字。不过,要真正稳定生成器,我们还需要回答一些有趣的问题,即如何为异步iteration trait 进行最佳设计。多亏了 trait 中 async fn 的稳定化,我们现在可以进行这样的交流–而且我们确实一直在进行这样的交流!在过去的一个多月里,我们还就最佳设置进行了许多有趣的来回讨论。我还在消化所有的帖子,希望能在这个月提出一些想法(不保证)。无论如何,我认为我们有可能在 2024 年看到 async genreators 的出现,这将是一件好事,因为这将消除人们与 Pin 直接交互的主要原因。

结论:展望 2024 年

如果我们实现了上述目标,那么到 2024 年底,async Rust 将大有改进。但是,在我们真正完成所需的部分之前,仍有一些大项目需要完成。遗憾的是,我们不可能做到这一切,所以这些项目将不得不等到 2024 年之后,尽管我认为我们会继续实验和讨论它们的设计:

Async drop: 有了异步闭包之后,还有一个地方无法编写异步函数,那就是 Drop trait 。Async drop 有很多有趣的复杂问题(Sabrina 就此写了一篇很棒的博文!),但它也是用户的一大痛点。下面我们就来了解一下!

Dyn async trait:除了send bounds,,trait 中 async fn 的另一个主要限制是使用它们的 trait 尚不支持动态派发。我们绝对应该取消这一限制,但对我来说,它的优先级较低,因为现有的解决方法是使用 proc-macro 创建 DynAsyncTrait 类型。这并不理想,但它并不像send bounds,或缺乏 async closures和async drop那样是一个根本性的限制。(尽管如此,这方面的设计工作已基本完成,因此我们完全有可能在今年将其作为一项即兴工作加以实现)。

Traits for being generic over runtimes: Async Rust 能够支持 TokioEmbassy 等不同的运行时,这是它的优势之一。但事实上,切换运行时或编写generic 运行时的代码非常困难,甚至不可能,这是一个关键的痛点,而运行时往往不能很好地协同工作,这就更糟糕了。我们需要为interop建立trait ,从[异步读写]开始,最终覆盖[任务生成和定时器]。

更好的APIs:当用户试图管理嵌套任务时,会出现许多最糟糕的异步 Rust Bug。现有的应用程序接口(如 FutureUnordered 和 select)有很多粗糙的边缘情况,很容易导致死锁–Tyler 曾就此发表过一篇很好的文章。我希望我们能重新审视为 Rust 程序员提供的异步 API,并建立一个功能强大、易于使用的库,帮助用户远离潜在的死锁源。理想情况下,这种 API 不会针对底层运行时,而是让用户在不同运行时之间切换,并希望能干净利落地支持嵌入式系统(也许功能有限)。我认为我们还不知道如何做到这一点,而且我认为要做到这一点,我们还需要更多的工具(如send bounds,async closure,以及很可能的 trait transformers 或 async drop)。

本文文字及图片出自 What I'd like to see for Async Rust in 2024


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK