Rust Async 3- 繼續理解 Async

            異步編程允許我們在同一個系統線程上所謂的同時運行多個任務,實現這個功能的訣竅就是當 CPU 等待外部事件或動作時(例如等待讀寫文件到磁盤、等待網絡數據達到、等待定時器完成等),也就是一段代碼或一個函數在等待的同時,異步運行時(例如 tokio)會安排其他可繼續執行的任務在 CPU 上執行。而當從磁盤或 I/O 子系統的系統中斷到達的時候,異步運行時會知道識別這事,並安排原來的任務繼續執行。

一般來說,I/O 受限(I/O Bound)的程序(程序執行的速度依賴於 I/O 子系統的速度)比起 CPU 受限(CPU Bound)的任務(程序執行的速度依賴於 CPU 的速度)可能更適合於異步任務的執行。但這只是一個一般的指導方針,也有例外。

async、.await 關鍵字是 Rust 標準庫裏用於異步編程的內置核心原語集的代表。他們其實就是 Rust 裏面特殊的語法糖,使開發人員更容易編寫類似同步代碼的異步代碼。

而 Rust 異步的核心其實是 Future。Future 是由異步計算或函數產生的單一最終值。Rust 的異步函數都會返回 Future,Future 基本上就是代表着延遲的計算。

我們之前的例子使用 Future 了嗎?簡單來說,是的。我們把之前的程序改一下寫法:

      針對之前異步的例子代碼,本例中我們沒有修改 main 函數的代碼,也就是說對 read_file1() 和 read_file2() 函數的調用代碼沒有變。而這兩個函數簽名改變了:

·      函數前 async 關鍵字去掉了;

·      函數返回值從 String 改爲 impl Future<Output=String>,也就是要求返回類型實現 Future 這個 trait,最終的返回值類型是 String;

·      原來函數體裏的內容都套在了一個 async 塊內(在函數或代碼塊前使用 async 關鍵字就會告訴編譯器把代碼轉化爲讓其可以生成 Future)。

而這個例子的執行結果和之前異步例子是一樣的:

其實下面第一種寫法就是第二種寫法的語法糖而已:

下面我們看一下 Future 的代碼:

      Future 就代表着異步的計算,其中的 Output 表示 Future 成功完成後返回的數據類型。

      poll 方法對於異步程序非常重要。poll 是被異步運行時調用,用來檢查異步任務是否已經完成。poll 方法返回一個枚舉,該枚舉有兩個變體:

      其中 Pending 表示 Future 還沒有完成;而 Ready 表示 Future 已經完成,它裏面存放着返回的值。

      那麼,誰來調用 poll 方法呢?Rust 的 Future 需要有人不斷跟進驅動 Future 來完成,就像一個事無鉅細的項目經理。

      做這件事的就是異步執行器,它是異步運行時的一部分。異步執行器會管理一堆 Future,並通過調用 Future 上的 poll 方法來驅動他們完成。所以函數或代碼塊在前面加上 async 關鍵字之後,就相當於告訴異步執行器(例如 tokio 的執行器)他會返回 Future,這個 Future 需要被驅動直到完成。

      但是異步執行器(例如 tokio 的執行器)怎麼知道異步已經準備好可以取得進展(可以產生值)了呢?他會持續不斷的調用 poll 方法嗎?臥槽這麼做不累嗎?

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/d6hw3K5_xPF8Gc9ZxF9tXg