Rust语言异步编程简介 - Shakaib


我认为可以肯定地说,Rust最令人期待的语言功能之一终于落地了。我假设您一些有关Rust的语法和生态系统的基础知识。但是在深入研究编码部分之前,让我们用Async的定义介绍异步编程的一些基本概念。

异步定义:
在Rust中,异步意味着不等待其他任务完成,因为它可以在单个线程上同时运行多个任务。多线程就是这样,当您有计算量大的任务(所谓的CPU绑定任务)时使用多线程;但是IO绑定则是花费大量时间等待的任务,例如服务器的响应,异步编程使我们可以在单个线程上同时运行多个IO绑定计算,而不会浪费任何时间,因为当它们等待响应时,它们只是空闲的,因此借助异步,我们可以让计算机保持工作状态。

为什么要使用异步Rust
关于Rust的一个值得注意的观点是出色的并发。有权执行并发事务而不放弃安全性。同样,Rust是一种低级语言,它无需选择特定的实现策略即可实现出色的并发。这意味着如果我们想在不同策略的用户之间共享代码,则必须对策略进行抽象以允许以后进行选择。
Futures抽象策略:他们描述了“什么”,而与“何处”和“何时”无关。为此,他们的目标是将代码分解为可以由我们系统的一部分执行的小型可组合动作。

use async_std::task;
// ^ we need this for task spawning
async fn negate_async(n: i32) -> i32 {
  println!(“Negating {}”, n);
  task::sleep(std::time::Duration::from_secs(5)).await;
  println!(“Finished sleeping for {}!”, n);
  n * -1
}
async fn f() -> i32 {
  let neg = negate_async(1);
 
// … nothing happens yet
  let neg_task = task::spawn(negate_async(2));
 
// ^ this task /is/ started
  task::sleep(std::time::Duration::from_secs(1)).await;
 
// we sleep for effect.
  neg.await + neg_task.await
 
// ^ this starts the first task `neg`
 
// and waits for both tasks to finish
}

  • ·第一行导入async_std :: task。
  • async异步函数negate_async()接受输入一个带符号的整数,休眠5秒钟,然后返回该整数的取反版本。
  • async异步函数f()更有趣:

  1. 第一行(let neg…)创建negate_async函数的Future并将其分配给neg变量。重要的是,它尚未开始执行。
  2. 下一行代码(let neg_task…)使用task :: spawn函数开始执行negate_async返回的Future。与neg一样,negate_async返回的Future分配给neg_task变量。
  3. 接下来:我们睡一秒钟。这样一来,当任务开始运行时,输出中将很明显。
  4. 最后,我们等待两个future,将它们加在一起,然后返回。通过等待,我们开始执行Future并将其运行到完成。由于neg_task已经启动,因此我们等待它完成。

那么,结果是什么呢?

Negating 2
# <- there’s a 1 second pause here
Negating 1
Finished sleeping for 2!
Finished sleeping for 1!

正如我们所看到的,第二个future函数neg_task在刚被调用时就开始执行,这要归功于task :: spawn,而neg直到等待结束才开始执行。

如何在Rust中使用async-await:
您可能熟悉JavaScript或C#中的async-await。Rust的功能版本相似,但主要区别不大。
要使用async-await,您可以通过异步fn而不是普通fn开始写入。

async fn first_function() -> u32 { .. }

与常规函数不同,调用异步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以等待将来的结果并传播错误。它还具有使方法链接变得无痛的优势。

结论:
我们相信,对Rust进行稳定的异步等待将成为Rust中许多新的令人振奋的开发的关键推动力。如果您过去在Rust中尝试过异步I / O并遇到了问题-特别是如果您尝试了过去基于组合器的未来-您会发现async-await与Rust的借用系统集成得更好