《C#併發編程經典實例》學習筆記—非同步編程關鍵字 Async和Await

来源:https://www.cnblogs.com/AlienXu/archive/2018/08/24/9529541.html
-Advertisement-
Play Games

C 5.0 推出async和await,最早是.NET Framework 4.5引入,可以在Visual Studio 2012使用。在此之前的非同步編程實現難度較高,async使非同步編程的實現變得簡便。 各平臺對async的支持情況 |平臺|async| | | | |.NET 4.5及以上|& ...


C# 5.0 推出async和await,最早是.NET Framework 4.5引入,可以在Visual Studio 2012使用。在此之前的非同步編程實現難度較高,async使非同步編程的實現變得簡便。

各平臺對async的支持情況

平臺 async
.NET 4.5及以上
.NET 4.0 NuGet
Mono iOS/Droid
Windows Store
Windows Phone Apps 8.1
Windows Phone SL 8.0
Windows Phone SL 7.1 NuGet
Silverlight 5 NuGet

在不支持的平臺,安裝NuGet包 Microsoft.Bcl.Async

使用 async 修飾符可將方法、lambda 表達式或匿名方法指定為非同步。

async 對方法做了什麼處理

從使用async修飾符修飾的方法的IL代碼可以得出一個結論:

  • 在Debug下,針對async方法,生成的是一個class狀態機
  • 在Release下,針對async方法,生成的是一個struct狀態機

舉例:
C#代碼如下

using System.Threading.Tasks;

namespace ConsoleApp3
{
    public class Test
    {
        public async Task TestAsync()
        {
            await GetAsync();
        }

        public async Task GetAsync()
        {
            await Task.Delay(1);
        }
    }
}

以TestAsync方法為準

Release下 初始化狀態機V_0 ,類型是值類型Struct(valuetype),類型名稱為<TestAsync>d__0

    .locals init (
      [0] valuetype ConsoleApp3.Test/'<TestAsync>d__0' V_0,
      [1] valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder V_1
    )

<TestAsync>d__0 繼承值類型[mscorlib]System.ValueType

.class nested private sealed auto ansi beforefieldinit 
    '<TestAsync>d__0'
      extends [mscorlib]System.ValueType
      implements [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine

Debug 下 初始化狀態機V_0 ,類型是引用類型Class(class) ,類型名稱為<TestAsync>d__0

    .locals init (
      [0] class ConsoleApp3.Test/'<TestAsync>d__0' V_0,
      [1] valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder V_1
    )

<TestAsync>d__0 繼承引用類型[mscorlib]System.Object

  .class nested private sealed auto ansi beforefieldinit 
    '<TestAsync>d__0'
      extends [mscorlib]System.Object
      implements [mscorlib]System.Runtime.CompilerServices.IAsyncStateMachine

非同步方法的定義和註意事項

使用 async 關鍵字定義的非同步方法簡稱為“非同步方法”。

註意事項:

  • 如果 async 關鍵字修改的方法不包含 await 表達式或語句,則該方法將同步執行。 編譯器警告將通知你不包含 await 語句的任何非同步方法,因為該情況可能表示存在錯誤。 請參閱編譯器警告(等級 1)CS4014
  • async 關鍵字是上下文關鍵字,原因在於只有當它修飾方法、lambda 表達式或匿名方法時,它才是關鍵字。 在所有其他上下文中,都會將其解釋為標識符。
  • 不要用 void 作為 async 方法的返回類型! async 方法可以返回 void ,但是這僅限於編寫事件處理程式。一個普通的 async 方法如果沒有返回值,要返回Task ,而不是 void
  • 一定要避免使用Task.WaitTask<T>.Result 方法,因為它們會導致死鎖。如果使用了 async ,最好就一直使用它。
  • 非同步方法的參數不能使用outrefoutref 返回的數據應借用Task<TResult> 返回,可以使用元組或自定義數據結構。

非同步方法的特征

  • 方法簽名包含 async 修飾符。
  • 按照約定,非同步方法的名稱以“Async”尾碼結尾。
  • 返回類型為下列類型之一:
    • 如果你的方法有操作數為 TResult 類型的返回語句,則為 Task<TResult>
    • 如果你的方法沒有返回語句或具有沒有操作數的返回語句,則為 Task
    • void:如果要編寫非同步事件處理程式。
    • 包含 GetAwaiter 方法的其他任何類型(自 C# 7.0 起)。
  • 方法通常包含至少一個 await 表達式,該表達式標記一個點,在該點上,直到等待的非同步操作完成方法才能繼續。 同時,將方法掛起,並且控制返回到方法的調用方。

關於async和await具體的執行流程,方法何時掛起和釋放,請參考非同步程式中的控制流 (C#)

非同步返回類型

上面提到 void 作為返回結果,適用於事件處理程式。
舉例:

using System;
using System.Threading.Tasks;

namespace ConsoleApp3
{
    public class TestVoidAsync
    {
        private event EventHandler<EventArgs> DoTest;

        public TestVoidAsync()
        {
            DoTest += DoTestEvent;
        }

        private static async void DoTestEvent(object sender, EventArgs e)
        {
            await Task.Delay(1000);
        }

        protected virtual void OnDoTest()
        {
            DoTest?.Invoke(this, EventArgs.Empty);
        }
    }
}

void 作為返回結果存在一個弊端:無法捕獲異常。

返回 void 的非同步方法的調用方無法捕獲從該方法引發的異常,且此類未經處理的異常可能會導致應用程式故障。 如果返回 TaskTask<TResult> 的非同步方法中出現異常,此異常將存儲於返回的任務中,併在等待該任務時再次引發。

通用的非同步返回類型:

從 C# 7.0 開始,非同步方法可返回任何具有可訪問的 GetAwaiter 方法的類型。

ValueTask<TResult>

Task 和 Task<TResult> 是引用類型,因此,性能關鍵路徑中的記憶體分配會對性能產生負面影響,尤其當分配出現在緊湊迴圈中時。 支持通用返回類型意味著可返回輕量值類型(而不是引用類型),從而避免額外的記憶體分配。

使用ValueTask<TResult>,需要添加NuGet包 System.Threading.Tasks.Extensions

ValueTask<TResult> 是struct值類型,Task 和 Task<TResult> 是class引用類型

非同步操作的生命周期

Task 類提供了非同步操作的生命周期,且該周期由 TaskStatus 枚舉表示。

狀態 執行順序 備註
Created 0 該任務已初始化,但尚未安排。
WaitingForActivation 1 該任務正在等待被.NET Framework infrastructure 內部激活和調度。
WaitingToRun 2 該任務已安排執行但尚未開始執行。
Running 3 任務正在運行但尚未完成。
WaitingForChildrenToComplete 4 任務已完成執行,並隱式等待附加的子任務完成。
RanToCompletion 5 任務已成功完成執行。
Canceled 6 引發 OperationCanceledException 異常,或者在任務開始執行之前取消
Faulted 7 由於未處理的異常,任務已完成。

Canceled 和 Faulted狀態都會因為任務異常導致轉換為該狀態。二者的區別如下:

如果標記的 IsCancellationRequested 屬性返回 false,或者異常的標記與任務的標記不匹配,則會將 OperationCanceledException 按照普通的異常來處理,從而導致任務轉換為 Faulted 狀態。 另外還要註意,其他異常的存在將也會導致任務轉換為 Faulted 狀態。 您可以在 Status 屬性中獲取已完成任務的狀態。

參考文章:


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

-Advertisement-
Play Games
更多相關文章
  • 1.先在VS 的擴展更新中搜索此插件【2015 installer Projects】,點擊下載,安裝需要關閉VS 2.安裝完畢之後新建項目 3.選擇“application folder”項,然後在右邊的空白區域右擊,選擇Add,如下圖 4.選擇需要打包發佈的exe文件 這裡會自動帶出相關聯的dl ...
  • using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace FB.CMS.MvcSite.App_Start { using Autofac; using Autofac... ...
  • 第一次發佈MVC項目,打開網站 未能載入文件或程式集“System.Web.Http.WebHost, Version=4.0.0.0, ”或它的某一個依賴項。系統找不到指定的文件。 問題原因:缺少配置文件(System.Net.Http.Formatting.dll,System.Web.Http ...
  • 一、要做成什麼樣 bs端的輪播控制項千千萬,有的甚至能作為一個單獨的庫來開發,所涉及到的功能也是繽紛多彩。相對來說,cs端的輪播用得不多,我這裡只是簡單的做了個能滿足一般需求的輪播,在項目中湊會湊會還是可以的。先給兩張圖,看看最後的效果: 如圖,整個結構就是左右箭頭、底部小點以及內同三大部分。雖然是簡 ...
  • 2018-08-24 c#金額轉換成中文大寫金額 decimal PriceSum = 32957.2654; 調用 var PriceSumChinese = MoneyToUpper(PriceSum.ToString()); 結果:叄萬貳仟玖佰伍拾柒圓貳角柒分 ...
  • 前言 List集合操作去除重覆數據的這種情況經常會碰到,博客園裡面也有很多大神們做過,在這裡主要是借鑒然後自己整理了一下,主要是為了方便自己,以後再次碰到這種去重問題,直接打開自己的鏈接拿起鍵盤就是乾,,,, 一、方法一 利用HashSet去重,在實體類里重寫Equals和GetHashCode方法 ...
  • 前言 前面講解了MEF的引用方法,介面的導入導出,類屬性的導入導出和集合的導出用法其實大家可以看到基本上大同小異的。 MEF的延遲載入 我們知道當裝配一個組件的時候,當前組件裡面的所有的Import的變數都自動去找到對應的Export而執行了實例化,有些時候出於程式效率的考慮,不需要立即實例化對象, ...
  • MEF導出類的方法和屬性 首先來說導出屬性,因為這個比較簡單,和導出類差不多,先來看看代碼,主要看我加註釋的地方,MusicBook.cs中的代碼如下: program.cs中的代碼如下: 下麵還用foreach遍歷輸出屬性的值,運行即可查看到結果。最後我會附上源碼供大家下載,這裡就不再截圖了。 下 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...