iT邦幫忙

0

.NET 併發處理 Async/Await 隨筆 02

  • 分享至 

  • xImage
  •  

筆記:.NET 併發處理 Async/Await 隨筆 02

上篇筆記裡有寫到,如果程式的瓶頸點是在 I/O Bound 的話,可以考慮使用 async/await 來處理。

這個筆記想寫一下,其實 .net async/await 在實作時,還是有不少的開銷,如果發現自己已經找不到程式還可以 tune 些什麼來把量往上拉的話,另一個思考的方向就是……可能可以考慮換個程式語言。

使用狀態機的 .net async/await

.net 的 async/await 其實是一種語法糖,底層裡是透過 狀態機(state machine) 來實作。編譯時,編譯機就會把程式碼拆成多個區塊,然後用變數來記錄各個要執行的區塊。長像就像下面的 switch 程式區塊。

switch (state)
{
    case 0:
        // do 程式區塊1
        break;
    case 1:
        // do 程式區塊2
        break;
    case 2:
        // do 程式區塊3
        break;
}

所以程式每跑到一個 await 的區塊再接著回來執行時,就會進到 switch case 的判斷來看說接下來要繼續執行哪一段程式。(有時候不一定會有切換的動作,因為 await 後面緊接著的程式有可能跑得很快,快到 await 可以直接再接著做接下來的程式)

這裡的細節是,如果有進行切換的動作,那原本這條 thread 在 stack 裡的資料總是要找地方放才行(因為它待會還會用到)。這時候 .net 就會把這些資料先存到 heap 上,然後再把 thread 放回去 thread pool。等 I/O 動作完成的時候,接著執行程式的 thread 必須要有之前的 stack 資料才行,所以就又要再從 heap 上把資料拿回來,然後再繼續執行後面的程式。

這個資料流動 stack=>heap=>stack 搬來搬去的動作,在想要更高併發量的程式裡,有時候就是需要講究。或是理解它會有這個動作,才可以在架構設計裡的技術選型做一些取捨。

註:這裡還沒有算進程式跑到 await 的時候,thread 需要在 user mode & kernel mode 之間切換的成本。(因為我也還沒研究到那麼透徹,不好寫~)


心得

為什麼要再特別筆記 async/await 的實作機制,是因為之後想再記錄一個 golang 非同步處理的筆記,讓自己在之後的技術選型的時候能有不同的選擇跟考量。

個人感覺,因為時空背景的不同, golang 語言在設計時,就是一種想盡辦法要把機器榨到乾的感覺。這種榨到乾不是粗爆版的狂操它,而是不浪費那任何一丁點的屑屑資源。

所以像 .net 的非同步處理還在靠作業系統的 scheduler 來處理 thread 的切換時,golang 已經自己實作一套 scheduler 的機制,可以不用依賴作業系統的 scheduler。

當然,不那麼講究的話,用金錢的力量把機器變多台,也是一個 solution。but...我是講究的工程師。


參考資料

筆記:.NET 併發處理 Async/Await 筆記


圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言