投稿 刀哥 Rust學習筆記 4

2021-10-23 17:44:47 字數 2967 閱讀 6196

@[toc](rust 學習心得<4>:async/await 如何工作)

2023年底rust正式支援 async/await語法,完成了rust協程的最後一塊拼圖,從而非同步**可以用一種類似於go的簡潔方式來書寫。然而對於程式設計師來講,還是很有必要理解async/await的實現原理。

簡單地說,async語法生成乙個實現future物件。如下async函式:

async fn foo() ->
async關鍵字,將函式的原型修改為返回乙個future trait object。然後將執行的結果包裝在乙個新的future中返回,大致相當於:

fn foo() -> impl future

}

更重要的是async**塊會實現乙個匿名的future trait object,包裹乙個generator。也就是乙個實現了futuregeneratorgenerator實際上是乙個狀態機,配合.await當每次async**塊中任何返回poll::pending則即呼叫generator yeild,讓出執行權,一旦恢復執行,generator resume繼續執行剩餘流程。

以下是這個狀態機future的**:

pub const fn from_generator(gen: t) -> impl futurewhere

t: generator,

impl> future for genfuture;

match gen.resume(resumety(nonnull::from(cx).cast::>())) }}

genfuture(gen)

}

可以看到這個特別的future是通過generator來執行的。每一次gen.resume()會順序執行async block中**直到遇到yieldasync block中的.await語句在無法立即完成時會呼叫yield交出控制權等待下一次resume。而當所有**執行完,也就是狀態機進入completeasync block返回poll::ready,代表future執行完畢。

每乙個await本身就像乙個執行器,在迴圈中查詢future的狀態。如果返回pending,則yield,否則退出迴圈,結束當前future

**邏輯大致如下:

loop 

}

為了更好地理解async/await的原理,我們來看乙個簡單例子:

async fn foo()
使用async修飾的非同步函式foo被改寫為乙個generator狀態機驅動的future,其內部有乙個some_future.await,中間穿插do_something_x()等其他操作。當執行foo().await時,首先完成do_something_1(),然後執行some_future.await,若some_future返回pending,這個pending被轉換為yield,因此頂層foo()暫時也返回pending,待下次喚醒後,foo()呼叫resume()繼續輪詢some_future,若some_future返回ready,表示some_future.await完畢,則foo()開始執行do_something_2()

這裡的關鍵點在於,因為狀態機的控制,所以當foo()再次被喚醒時,不會重複執行do_something_1(),而是會從上次yield的的地方繼續執行some_future.await,相當於完成了一次任務切換,這也是無棧協程的工作方式。

async/await通過乙個狀態機來控制**的流程,配合executor完成協程的切換。在此之後,書寫非同步**不需要手動寫future及其poll方法,特別是非同步邏輯的狀態機也是由async自動生成,大大簡化程式設計師的工作。雖然async/await出現的時間不長,目前純粹使用async/await書寫的**還不是主流,但可以樂觀地期待,今後更多的專案會使用這個新語法。

參考 futures explained in 200 lines of rust

Rust學習筆記

toc rust學習筆記 初步閱讀rust的 以學習rust語言 match 採用表示式的形式,然後根據它的值來分支。分支的每個 臂 都是 val expression 的形式。當值匹配時,這個臂的表示式將被執行實現。之所以稱之為 match 是因為 模式匹配 的術語,而這種正是 match 實現的...

Rust學習筆記1

use rand rng use std cmp ordering use std io fn main println 輸入數字 input match input.cmp guess ordering greater println 高了 ordering less println 低了 對比c...

rust筆記4 slice型別

先給出個例子 fn main n n n n slice0,slice1,slice2,slice3,slice4 輸出結果 hello hello world world hello world 切片的區間是左閉右開,而且切片是引用型別的,這相當於位址的乙個範圍,所以我們使用 s的方式來表示。字串...