前言
微信群裡的一個提問引發的這個問題,有同學問:C#非同步有多少種實現方式?想要知道C#非同步有多少種實現方式,首先我們要知道.NET提供的執行非同步操作的三種模式,然後再去了解C#非同步實現的方式。
.NET非同步程式設計模式
.NET 提供了執行非同步操作的三種模式:
-
基於任務的非同步模式 (TAP) ,該模式使用單一方法表示非同步操作的開始和完成。 TAP 是在 .NET Framework 4 中引入的。 這是在 .NET 中進行非同步程式設計的推薦方法。 C# 中的 async 和 await 關鍵詞以及 Visual Basic 中的 Async 和 Await 運算子為 TAP 新增了語言支援。 有關詳細資訊,請參閱基於任務的非同步模式 (TAP)。
-
基於事件的非同步模式 (EAP),是提供非同步行為的基於事件的舊模型。 這種模式需要字尾為
Async
的方法,以及一個或多個事件、事件處理程式委託型別和EventArg
派生型別。 EAP 是在 .NET Framework 2.0 中引入的。 建議新開發中不再使用這種模式。 有關詳細資訊,請參閱基於事件的非同步模式 (EAP)。 -
非同步程式設計模型 (APM) 模式(也稱為 IAsyncResult 模式),這是使用 IAsyncResult 介面提供非同步行為的舊模型。 在這種模式下,同步操作需要
Begin
和End
方法(例如,BeginWrite
和EndWrite
以實現非同步寫入操作)。 不建議新的開發使用此模式。 有關詳細資訊,請參閱非同步程式設計模型 (APM)。
C#非同步有四種實現方式
C# 非同步有多種實現方式,可歸納為以下幾類:
1、非同步方法(Async Method TAP模式)
使用async/await關鍵字實現非同步程式設計,這是比較常用的一種非同步實現方式。例如:
public async Task TestDoSomeAsync() { await Task.Delay(1000*10); Console.WriteLine("Async method completed."); }
2、任務並行庫(TPL, Task Parallel Library TAP模式)
透過 Task 和 Task<T> 型別實現非同步程式設計,可以利用多核處理器,併發執行多個獨立的任務。例如:
public static void TestTaskParallel() { var task1 = Task.Run(() => { Console.WriteLine("Task 1 completed."); }); var task2 = Task.Run(() => { Console.WriteLine("Task 2 completed."); }); Task<int> task3 = Task.Factory.StartNew(() => { Console.WriteLine("Task 3 completed."); return 20;// 返回一個整數值 }); //等待所有任務完成 Task.WaitAll(task1, task2, task3); }
3、Asynchronous Programming Model(APM模式)
是一種經典的非同步程式設計模式,需要手動建立回撥函式,用於處理完成或錯誤的通知。可以透過 IAsyncResult 設計模式的 Begin 和 End 方法來實現,其中 Begin 方法開始非同步操作,而 End 方法在非同步操作完成時執行,並返回非同步操作的結果。
需要注意的是,APM 模式透過 IAsyncResult 介面來儲存非同步操作的狀態和結果,相對比較複雜,程式碼量也較大。同時,在使用 APM 模式時,還需要手動處理回撥函式和等待非同步操作完成等細節工作,使得開發起來相對較為繁瑣。
class Program { static void Main(string[] args) { // 建立非同步操作類例項 MyAsyncClass asyncClass = new MyAsyncClass(); // 開始非同步操作 IAsyncResult result = asyncClass.BeginDoWork(null, null); // 主執行緒執行其他操作 // 等待非同步操作完成並獲取結果 int res = asyncClass.EndDoWork(result); // 處理非同步操作的結果 Console.WriteLine("Result: " + res); Console.ReadLine(); } } class MyAsyncClass { /// <summary> /// 非同步執行的方法 /// </summary> /// <param name="callback">callback</param> /// <param name="state">state</param> /// <returns></returns> public IAsyncResult BeginDoWork(AsyncCallback callback, object state) { // 建立一個新的非同步操作物件 MyAsyncResult result = new MyAsyncResult(state); // 開始非同步操作 Thread thread = new Thread(() => { try { // 執行一些操作 int res = 1 + 2; // 設定非同步操作的結果 result.Result = res; // 觸發回撥函式 callback?.Invoke(result); } catch (Exception ex) { // 設定非同步操作的異常 result.Error = ex; // 觸發回撥函式 callback?.Invoke(result); } }); thread.Start(); // 返回非同步操作物件 return result; } /// <summary> /// 結束非同步執行的方法 /// </summary> /// <param name="result">result</param> /// <returns></returns> public int EndDoWork(IAsyncResult result) { // 將 IAsyncResult 轉換為 MyAsyncResult 型別,並等待非同步操作完成 MyAsyncResult myResult = (MyAsyncResult)result; myResult.AsyncWaitHandle.WaitOne(); // 在非同步操作中丟擲異常 if (myResult.Error != null) { throw myResult.Error; } // 返回非同步操作的結果 return myResult.Result; } } class MyAsyncResult : IAsyncResult { public bool IsCompleted => AsyncWaitHandle.WaitOne(0); public WaitHandle AsyncWaitHandle { get; } = new ManualResetEvent(false); public object AsyncState { get; } public bool CompletedSynchronously => false; public int Result { get; set; } /// <summary> /// 儲存非同步操作的結果或異常資訊 /// </summary> public Exception Error { get; set; } /// <summary> /// 建構函式 /// </summary> /// <param name="asyncState">asyncState</param> public MyAsyncResult(object asyncState) { AsyncState = asyncState; } }
4、Event-based Asynchronous Pattern(EAP模式)
一種已過時的非同步程式設計模式,需要使用事件來實現非同步程式設計。例如:
需要注意的是,EAP 模式透過事件來實現非同步程式設計,相對於 APM 模式更加簡潔易懂,同時也避免了手動處理回撥函式等細節工作。但是,EAP 模式並不支援 async/await 非同步關鍵字,因此在一些特定的場景下可能不夠靈活。
public class MyAsyncClass : Component { /// <summary> /// 宣告一個委託型別,用於定義非同步操作的方法簽名 /// </summary> /// <param name="arg"></param> /// <returns></returns> public delegate int MyAsyncDelegate(int arg); /// <summary> /// 宣告一個事件,用於通知非同步操作的完成 /// </summary> public event MyAsyncDelegate OperationNameCompleted; /// <summary> /// 非同步執行方法,接受一個引數 arg /// </summary> /// <param name="arg"></param> public void DoWorkAsync(int arg) { // 將非同步操作放入執行緒池中執行 ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork), arg); } /// <summary> /// 真正的非同步操作 /// </summary> /// <param name="obj"></param> private void DoWork(object obj) { int arg = (int)obj; int res = arg + 1; // 觸發事件,傳遞非同步操作的結果 OperationNameCompleted?.Invoke(res); } }
參考文章
https://learn.microsoft.com/zh-cn/dotnet/standard/asynchronous-programming-patterns/