C#非同步有多少種實現方式?

追逐時光者發表於2023-05-09

前言

  微信群裡的一個提問引發的這個問題,有同學問: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/

 

 

相關文章