利用 async await 的非同步程式設計

2021-08-20 08:29:45 字數 4363 閱讀 4163

通過使用非同步程式設計,你可以避免效能瓶頸並增強你的應用程式的總體響應能力。

從 vs 2012 開始,新引入了乙個簡化的方法,稱為非同步程式設計。我們在 >= .net 4.5 中和 windows 執行時中使用非同步,編譯器它會幫助了我們降低了曾經進行的高難度非同步**編寫的工作,但邏輯結構卻類似於同步**。因此,我們僅需要進行一小部分程式設計的工作就可以獲得非同步程式設計的所有優點。

非同步對可能引起阻塞的活動(如訪問 web 時),對 web 資源的訪問有時過慢或延遲過高。若這種任務在同步過程中受阻,則整個應用程式必須等待響應完成。 在使用非同步的過程中,我們的應用程式可繼續執行不依賴 web 資源的其他工作,並會一直等待阻塞的任務順利完成。

這是一些典型的使用非同步的應用場景,以及一些在 .net >= 4.5 後新增的類庫。

c# 中的 async 和 await 關鍵字都是非同步程式設計的核心。通過使用這兩個關鍵字,我們就可以在 .net 輕鬆建立非同步方法。

示例:

/// 2         /// 非同步訪問 web 

3 ///

4 ///

5 /// 6 /// 方法簽名的 3 要素:

7 /// ① async 修飾符

8 /// ② 返回型別 task 或 task:這裡的 task表示 return 語句返回 int 型別

9 /// ③ 方法名以 async 結尾

10 ///

11 async taskaccessthewebasync()

12

如果 accessthewebasync 在呼叫 getstringasync() 時沒有其它操作(如:**中的 do()),你可以用這樣的方式來簡化**。

string urlcontents = await client.getstringasync("

");

簡單總結:

(1)方法簽名包含乙個 async 修飾符。

(2)根據約定,非同步方法的名稱需要以「async」字尾為結尾。

(3)3 種返回型別:

① task:返回 tresult 型別。

② task:沒有返回值,即返回值為 void。

③ void:只適用於非同步事件處理程式。

(4)方法通常包含至少乙個 await 表示式,該表示式標記乙個點,我們可以成為懸掛點,在該點上,直到等待的非同步操作完成,之後的方法才能繼續執行。 與此同時,該方法將掛起,並將控制權返回到方法的呼叫方。

需要使用非同步方法的話,我們直接在系統內部使用所提供的關鍵字 async 和 await 就可以了,剩餘的其它事情,就留給編譯器吧。

非同步程式設計中最重要卻不易懂的是控制流,即不同方法間的切換。現在,請用一顆感恩的心來觀察下圖。

步驟解析:

① 事件處理程式呼叫並等待 accessthewebasync() 非同步方法。

③ 假設 getstringasync 中發生了某種情況,該情況掛起了它的程序。

getstringasync 返回 task,其中 tresult 為字串,並且 accessthewebasync 將任務分配給 getstringtask 變數。

該任務表示呼叫 getstringasync 的正在進行的程序,其中承諾當工作完成時產生實際字串值。

④ 由於尚未等待 getstringtask,因此,accessthewebasync 可以繼續執行不依賴於 getstringasync 得出最終結果的其他任務。

該任務由對同步方法 doindependentwork 的呼叫表示。

⑤ doindependentwork 是完成其工作並返回其呼叫方的同步方法。

⑥ accessthewebasync 已完成工作,可以不受 getstringtask 的結果影響。

因此,【備註】

如果 getstringasync(即 getstringtask)在 accessthewebasync 等待前完成,則控制權會保留在 accessthewebasync 中。

如果非同步呼叫過程 (getstringtask) 已完成,並且 accessthewebsync 不必等待最終結果,則掛起然後返回到 accessthewebasync,但這會造成成本的浪費。

在呼叫方內部(假設這是乙個事件處理程式),處理模式將繼續。在等待結果前,呼叫方可以開展不依賴於 accessthewebasync 結果的其他工作,否則就需等待片刻。事件處理程式等待 accessthewebasync,而 accessthewebasync 等待 getstringasync。

⑦ getstringasync 完成並生成乙個字串結果。

字串結果不是通過你預期的方式呼叫 getstringasync 所返回的。(請記住,此方法已在步驟 3 中返回乙個任務。)相反,字串結果儲存在表示完成方法 getstringtask 的任務中。 await 運算子從 getstringtask 中檢索結果。賦值語句將檢索到的結果賦給 urlcontents。

⑧ 當 accessthewebasync 具有字串結果時,該方法可以計算字串長度。

然後,accessthewebasync 工作也將完成,並且等待事件處理程式可繼續使用。 

你可以嘗試思考一下同步行為和非同步行為之間的差異。當其工作完成時(第 5 步)會返回乙個同步方法,但當其工作掛起時(第 3 步和第 6 步),非同步方法會返回乙個任務值。在非同步方法最終完成其工作時,任務會標記為已完成,而結果(如果有)將儲存在任務中。

非同步方法旨在成為非阻塞操作。非同步方法中的 await 表示式在等待的任務執行的同時不會阻塞當前執行緒。相反,await 表示式在繼續執行時方法的其餘部分並將控制權返回到非同步方法的呼叫方。

async 和 await 關鍵字不會導致建立其他執行緒。因為非同步方法不會在其自身執行緒上執行,因此它不需要多執行緒。只有當方法處於活動狀態時,該方法將在當前同步上下文中執行並使用執行緒上的時間。可以使用 task.run 將占用大量 cpu 的工作移到後台執行緒,但是後台執行緒不會幫助正在等待結果的程序變為可用狀態。

對於非同步程式設計而言,該基於非同步的方法優於幾乎每個用例中的現有方法。具體而言,此方法比 backgroundworker 更適用於 io 繫結的操作,因為此**更簡單且無需防止搶先爭用條件。結合 task.run() 使用時,非同步程式設計比 backgroundworker 更適用於 cpu 繫結的操作,因為非同步程式設計將執行**的協調細節與 task.run 傳輸至執行緒池的工作區分開來。

當你使用 async 修飾符指定該方法為非同步方法時:

在編寫非同步方法時,我們絕大部分會使用 task 和 task作為返回型別。

static async taskmethod1async()  //task

static async task method2async()  //task

//呼叫 method1async

//方式一

taskt1 = method1async();

guid guid1 = t1.result;

//方式二

guid guid2 = await method1async();

//呼叫 method2async

//方式一

task t2 = method2async();

await t2;

//方式二

await method2async();

每個返回的任務表示正在進行的工作。任務可封裝有關非同步程序狀態的資訊,如果未成功,則最後會封裝來自程序的最終結果,或者是由該程序引發的異常。

【疑問】那麼 void 返回型別是在什麼情況下才使用的呢?

主要用於非同步的事件處理程式,非同步事件處理程式通常作為非同步程式的起始點。void 返回型別告訴了編譯器,無需對他進行等待,並且,對於 void 返回型別的方法,我們也無法對他進行異常的捕捉。

非同步方法不能夠在引數中宣告與使用 ref 和 out 關鍵字,但是非同步方法可以呼叫包含這些引數的方法。

根據約定,使用 async 的方法都應該以「async」作為字尾,如:downloadasync() 。

但是,如果某一約定中的事件、基類或介面有其他的形式約定,則可以忽略上述約定。

例如,不應該修改或重新命名常用事件處理程式,如 btnopen_click。

非同步async await寫法

async await 用asyncio提供的 asyncio.coroutine可以把乙個generator標記為coroutine型別,然後在coroutine內部用yield from呼叫另乙個coroutine實現非同步操作。為了簡化並更好地標識非同步io,從python 3.5開始引入了新...

非同步操作async await

async函式的特點 例 router.get testasync async ctx 1000 const b await 123const c await new promise resolve,reject 2000 ctx.body 看看 的執行過程,它裡面遇到了await,await 表示...

同步非同步的理解 (async await)

近期在工作中使用同步非同步方法,出現bug,感覺以前對於同步非同步,阻塞非阻塞理解的有問題,於是在網上重新學習 找到以下的回答 同步 執行乙個操作之後,等待結果,然後才繼續執行後續的操作。非同步 執行乙個操作後,可以去執行其他的操作,然後等待通知再回來執行剛才沒執行完的操作。阻塞 程序給cpu傳達乙...