首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

.NET 非同步程式設計全景指南:從 APM 到 Task 的演進與實戰

     編輯:關於.NET

非同步模式分類

.NET 早期(1.0/2.0 時代)主要採用非同步程式模型(APM,Asynchronous Programming Model),即 BeginInvoke/EndInvoke 模式。本文系統梳理三種常見等待策略與回調模式。

場景一:需要在當前線程獲取返回值

1.1 啟動非同步 → 執行其他任務 → 最後獲取結果

delegate string AsyncFuncDelegate(int userInput);
static string Func(int userInput)
{
    Console.WriteLine("Func start to run");
    Thread.Sleep(5000);
    Console.WriteLine("Func end to run");
    return userInput.ToString();
}

static void Main()
{
    AsyncFuncDelegate caller = new AsyncFuncDelegate(Func);
    Console.WriteLine("Input number please...");
    IAsyncResult result = caller.BeginInvoke(Convert.ToInt32(Console.ReadLine()), null, null);
    Console.WriteLine("Implement other tasks");
    Thread.Sleep(7000); // 模擬其他工作
    Console.WriteLine("Implement other tasks end ...");
    Console.WriteLine("Get user's input");
    Console.WriteLine(caller.EndInvoke(result)); // 阻塞直到完成
    Console.ReadLine();
}

1.2 啟動非同步 → 任務 R1 → 等待完成 → 任務 R2 → 獲取結果

static void Main()
{
    AsyncFuncDelegate caller = new AsyncFuncDelegate(Func);
    IAsyncResult result = caller.BeginInvoke(Convert.ToInt32(Console.ReadLine()), null, null);
    Console.WriteLine("Implement task 1");
    result.AsyncWaitHandle.WaitOne(); // 等待信號
    result.AsyncWaitHandle.Close();   // 釋放資源
    Console.WriteLine("Implment task 2");
    Console.WriteLine("Get user's input");
    Console.WriteLine(caller.EndInvoke(result));
    Console.ReadLine();
}

1.3 啟動非同步 → 持續輪詢執行任務 R → 獲取結果

static void Main()
{
    AsyncFuncDelegate caller = new AsyncFuncDelegate(Func);
    IAsyncResult result = caller.BeginInvoke(Convert.ToInt32(Console.ReadLine()), null, null);
    while (!result.IsCompleted)
    {
        Thread.Sleep(1000);
        Console.Write(">"); // 進度指示
    }
    Console.WriteLine();
    Console.WriteLine("Implement other task2");
    Console.WriteLine("Get user's input");
    Console.WriteLine(caller.EndInvoke(result));
    Console.ReadLine();
}

場景二:不需要在當前線程獲取返回值,但需後續處理(回調模式)

static void Main()
{
    AsyncFuncDelegate caller = new AsyncFuncDelegate(Func);
    Console.WriteLine("Input number please...");
    caller.BeginInvoke(Convert.ToInt32(Console.ReadLine()), new AsyncCallback(CallBackFunc), "Message from Main thread.");
    Console.WriteLine("Main thread ends");
    Console.ReadLine();
}

static void CallBackFunc(IAsyncResult ar)
{
    AsyncResult result = ar as AsyncResult;
    string inputMessage = result.AsyncState as string;
    AsyncFuncDelegate caller = result.AsyncDelegate as AsyncFuncDelegate;
    Console.WriteLine("call back starts");
    Console.WriteLine(inputMessage);
    Console.WriteLine("The input number is : " + caller.EndInvoke(ar));
    Console.WriteLine("call back ends");
}

關鍵最佳實踐

  • 必須調用 EndInvoke:確保非同步操作正常結束,釋放資源,獲取返回值或傳播異常
  • 避免在 UI 線程同步等待:會導致介面凍結,優先使用回調或現代 async/await
  • 異常傳播:EndInvoke 會重新拋出非同步操作中發生的異常
  • 資源清理:AsyncWaitHandle 使用後需 Close()

現代化演進:Task 與 async/await

.NET 4.0+ 引入 Task、Task<T>,C# 5.0 引入 async/await,徹底改變非同步編程體驗:

// 現代寫法
public async Task FuncAsync(int userInput)
{
    await Task.Delay(5000);
    return userInput.ToString();
}

public async Task DemoAsync()
{
    var task = FuncAsync(42);
    Console.WriteLine("Implement other tasks");
    var result = await task; // 非阻塞等待
    Console.WriteLine("Result: " + result);
}

總結

從 APM 的 BeginInvoke/EndInvoke 到 TAP 的 Task/async/await,.NET 非同步編程經歷了巨大演進。理解經典模式有助於維護舊代碼,新專案應優先採用 Task 基礎模式,代碼更簡潔、可讀性更強、異常處理更自然。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved