.NET 早期(1.0/2.0 時代)主要採用非同步程式模型(APM,Asynchronous Programming Model),即 BeginInvoke/EndInvoke 模式。本文系統梳理三種常見等待策略與回調模式。
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();
}
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();
}
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");
}
async/awaitEndInvoke 會重新拋出非同步操作中發生的異常AsyncWaitHandle 使用後需 Close().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 基礎模式,代碼更簡潔、可讀性更強、異常處理更自然。