为什么要 async ?
优质
小牛编辑
125浏览
2023-12-01
我们都喜欢 Rust 允许我们编写快速,安全的软件。但是为什么要编写异步代码呢?
异步代码允许我们在同一 OS 线程上,同时运行多个任务。在典型的线程应用程序中,如果您想同时下载两个不同的网页,则需要将工作分散到两个不同的线程中,如下所示:
fn get_two_sites() {
// Spawn two threads to do work.
let thread_one = thread::spawn(|| download("https://www.foo.com"));
let thread_two = thread::spawn(|| download("https://www.bar.com"));
// Wait for both threads to complete.
thread_one.join().expect("thread one panicked");
thread_two.join().expect("thread two panicked");
}
这对许多应用程序都很好用 —— 毕竟,线程被设计为可以做到这一点:一次运行多个不同的任务。但是,它们也有一些限制。在不同线程之间切换,以及在线程之间共享数据的过程,涉及很多开销。即使只是一个坐着不执行任何操作的线程,也会占用宝贵的系统资源。这些就是异步代码旨在消除的成本。我们可以使用 Rust async
/.await
符号,重写上面的函数,这将使我们能够一次运行多个任务,而无需创建多个线程:
async fn get_two_sites_async() {
// Create two different "futures" which, when run to completion,
// will asynchronously download the webpages.
let future_one = download_async("https://www.foo.com");
let future_two = download_async("https://www.bar.com");
// Run both futures to completion at the same time.
join!(future_one, future_two);
}
总体而言,与相应的线程实现相比,异步应用程序可能具有更快的速度和更少的资源。但是,这是有成本的。线程受操作系统的原生支持,并且使用它们不需要任何特殊的编程模型 —— 任何函数都可以创建一个线程,且调用那些使用线程的函数,通常与调用任何普通函数一样容易。但是,异步功能需要语言或库的特殊支持。在 Rust 中,async fn
创建一个异步函数,该函数返回一个Future
。要执行该函数的主体(比如:网络 API 的数据),返回的Future
,必须运行(实际请求)到完成。
重要的是要记住,传统的线程应用程序可以非常高效,并且 Rust 的内存占用量小和可预测性,意味着您无需使用任何async
就能取得成功。异步编程模型的增加的复杂性,并不总是值得的,并且重要的是,考虑使用更简单的线程模型,是否可以为您的应用程序,更好地提供服务。