C#中await/async閑說

来源:https://www.cnblogs.com/zhao123/archive/2019/06/24/11078382.html
-Advertisement-
Play Games

自從C#5.0增加非同步編程之後,非同步編程越來越簡單,async和await用的地方越來越多,越來越好用,只要用非同步的地方都是一連串的非同步,如果想要非同步編程的時候,需要從底層開始編寫,這樣後邊使用的時候就是非同步,那麼底層是如何實現??我們如何編寫高效率的非同步方法?? #瞭解基於任務的非同步模式(TAP) ...


自從C#5.0增加非同步編程之後,非同步編程越來越簡單,async和await用的地方越來越多,越來越好用,只要用非同步的地方都是一連串的非同步,如果想要非同步編程的時候,需要從底層開始編寫,這樣後邊使用的時候就是非同步,那麼底層是如何實現??我們如何編寫高效率的非同步方法??

#瞭解基於任務的非同步模式(TAP)

基於任務的非同步編程模型 (TAP) 提供了非同步代碼的抽象化,你只需像往常一樣將代碼編寫為一連串語句即可,在開始調用的地方運行。例如:var task = method()①; await task②; 在①的時候開始運行可能還沒有運行完,在②程式掛起等待運行完,中間怎麼運行的你不需要知道,編譯器會做若幹操作的。當開啟多個任務的時候,像要他們都執行完,在執行其他的時候,可以await Task.WhenAll(task1,task2 .....);

#瞭解async/await

await 運算符應用於非同步方法,在方法的執行中插入掛起點,直到所等待任務完成。使用async 和await定義非同步方法不一定會創建新線程,當編譯器看到await關鍵字時,線程會掛起等待運行結束。
await 僅可用於由 async 關鍵字修改的非同步方法中,使用 async 修飾符定義的方法通常包含一個或多個 await 表達式,使用await運算符的任務通常是實現[基於任務的非同步模式(TAP)]的方法調用返回,返回值包括 Task、Task<TResult>、ValueTask 和 ValueTask<TResult> 對象的方法。

# 調用 Task.Wait() 或者 Task.Result 立刻產生死鎖的充分條件

1. 調用 Wait() 或 Result 的代碼位於 UI 線程。
2. Task 的實際執行在其他線程,且需要返回 UI 線程。
死鎖的原因:UWP、WPF、Windows Forms 程式的 UI 線程都是單線程的。為了避免產生死鎖,你應該一條道走到黑, Async All the Way。或者.ConfigureAwait(false)

# ValueTask與Task的區別

7.0為async新增的ValueTask的作用(如果沒有在Nuget上下載System.Threading.Tasks.Extensions,ValueTask就在這個庫中),ValueTask用於值類型的非同步;Task為引用類型的,每次需要分配空間。
例如:

public async Task<int> CalculateSum(int a, int b) {
    if (a == 0 && b == 0)
    {
        return 0;
    }

    return await Task.Run(() => a + b);
}

當a,b=0的時候不會運行到task里,這個時候返回task就造成了資源的浪費,修改為以下會效率更高

public async ValueTask<int> CalculateSum2(int a, int b)
{
    if (a == 0 && b == 0)
    {
        return 0;
    }

    return await Task.Run(() => a + b);
}

但是也不是說到處用ValueTask會好,當是引用類型的時候,用ValueTask,你需要關註更多的數據,這個時候用Task會更好。

# await/async原理分析

[AsyncStateMachine(typeof(Class1.<CalculateSum2>d__1))]
public ValueTask<int> CalculateSum2(int a, int b)
{
    Class1.<CalculateSum2>d__1 <CalculateSum2>d__;
    <CalculateSum2>d__.a = a;
    <CalculateSum2>d__.b = b;
    <CalculateSum2>d__.<>t__builder = AsyncValueTaskMethodBuilder<int>.Create();
    <CalculateSum2>d__.<>1__state = -1;
    AsyncValueTaskMethodBuilder<int> <>t__builder = <CalculateSum2>d__.<>t__builder;
    <>t__builder.Start<Class1.<CalculateSum2>d__1>(ref <CalculateSum2>d__);
    return <CalculateSum2>d__.<>t__builder.Task;
}

對CalculateSum2代碼解析,發現沒有await/async,原來又是編譯器提供的語法糖。

[__DynamicallyInvokable, DebuggerStepThrough, SecuritySafeCritical]
public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine
{
    if (stateMachine == null)
    {
        throw new ArgumentNullException("stateMachine");
    }
    ExecutionContextSwitcher executionContextSwitcher = default(ExecutionContextSwitcher);
    RuntimeHelpers.PrepareConstrainedRegions();
    try
    {
        ExecutionContext.EstablishCopyOnWriteScope(ref executionContextSwitcher);
        stateMachine.MoveNext();
    }
    finally
    {
        executionContextSwitcher.Undo();
    }
}

對Start方法進行分析,可以看出MoveNext,程式的運行其實還是一步一步進行的,那麼await/async會不會創建一個線程,這倒是不一定,這個由線程池決定,那麼非同步了不創建一個線程,怎麼非同步的,這裡的非同步可能是運行在已經有的線程上。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 6.9 time 模塊 1、時間戳(以秒計算) 2、格式化的字元串 3、struct_time()對象 4、 mktime( t ) : 將一個struct_time轉化為時間戳 5、time.strptime() 6、time.asctime() 7、time.ctime() 6.10 datet ...
  • 一、希爾排序的介紹 希爾排序(Shell Sort)是插入排序的一種。也稱縮小增量排序,是直接插入排序演算法的一種更高效的改進版本。希爾排序是非穩定排序演算法。 希爾排序是把記錄按下標的一定增量分組,對每組使用直接插入排序演算法排序;隨著增量逐漸減少,每組包含的記錄越來越多,當增量減至1時,整個文件恰被分 ...
  • 本篇內容說說Spring對切麵的支持,如何把普通類聲明為一個切麵,以及如何使用註解創建切麵,主要有以下幾點內容: 什麼是面向切麵編程 選擇連接點 使用註解創建切麵 在XML中聲明切麵 ...
  • 緩存要解決的問題是速度的問題,使用緩存的目的是為了減少對物理資源的訪問,緩存大量的應用在軟硬體的方方面面 ...
  • 1.面試要看資料下菜,人家不會的不要問 2.要調整自己做為面試官的心態,不是讓你去打敗面試者 3.要看薪酬調整面試提問的難易程度。 ...
  • 指定某個屬性使用特定的時間格式 Intro 是 .NET 下最受歡迎 JSON 操作庫,原為 後改名為 ,之前一直推薦大家使用,除了性能好之外,主要是功能豐富,基本滿足所有的可能用到的場景(不區分小寫,現在還不行,,)。 遇到這樣一個需求,全局使用一種時間格式,某些屬性使用特殊的時間格式,這裡以一個 ...
  • 上面的是父類,然後子類實現父類的構造函數,另外建一個類起名為SocketServer,繼承上一個類SocketHelper(此時SocketHelper為父類): OK,這樣就是子類繼承父類的構造函數 子類繼承父類的時候,其基類的構造函數,子類也要必須實現,不然會報錯 ...
  • 本文介紹“ 為ASP.NET Web API生成TypeScript客戶端API ”,重點介紹Angular 2+代碼示例和各自的SDLC。如果您正在開發.NET Core Web API後端,則可能需要閱讀為ASP.NET Core Web API生成C#Client API。 背景 自WebAp ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...