Rust語言非同步程式設計簡介 - Shakaib

banq發表於2020-06-01

我認為可以肯定地說,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的借用系統整合得更好
 

相關文章