.NET 早期異步模式(APM)通過委托的 BeginInvoke/EndInvoke 實現異步執行。BeginInvoke 立即返回 IAsyncResult,EndInvoke 獲取返回值或傳播異常。
delegate int NewTaskDelegate(int ms);
static int NewTask(int ms)
{
Console.WriteLine("任務開始");
Thread.Sleep(ms);
return new Random().Next(10000);
}
static void Main()
{
NewTaskDelegate task = NewTask;
IAsyncResult ar = task.BeginInvoke(2000, null, null);
int result = task.EndInvoke(ar); // 阻塞 2 秒
Console.WriteLine(result);
}
若不調用 EndInvoke,後台線程任務未完成進程就會退出。
IAsyncResult ar = task.BeginInvoke(2000, null, null);
while (!ar.IsCompleted)
{
Console.Write("*");
Thread.Sleep(100);
}
int result = task.EndInvoke(ar);
可在等待期間顯示進度,改善用戶體驗。
IAsyncResult ar = task.BeginInvoke(2000, null, null);
while (!ar.AsyncWaitHandle.WaitOne(100, false))
{
Console.Write("*");
}
int result = task.EndInvoke(ar);
WaitOne(100) 等待 100ms,超時返回 false,避免忙等待。
delegate int MyMethod();
private int Method()
{
Thread.Sleep(10000);
return 100;
}
private void Callback(IAsyncResult ar)
{
if (ar == null) return;
var del = (MyMethod)ar.AsyncState;
textBox1.Text = del.EndInvoke(ar).ToString();
}
private void Button_Click(object sender, EventArgs e)
{
MyMethod my = Method;
my.BeginInvoke(Callback, my); // 立即返回,UI 不凍結
}
回調方法在線程池線程中執行,訪問 UI 控件需注意跨線程調用(後續講解)。
如 HttpWebRequest.BeginGetResponse/EndGetResponse:
private void RequestCallback(IAsyncResult ar)
{
var req = (HttpWebRequest)ar.AsyncState;
var resp = (HttpWebResponse)req.EndGetResponse(ar);
var sr = new StreamReader(resp.GetResponseStream());
textBox1.Text = sr.ReadToEnd();
}
private void Button_Click(object sender, EventArgs e)
{
var req = (HttpWebRequest)WebRequest.Create("https://example.com");
req.BeginGetResponse(RequestCallback, req);
}
APM 模式雖已被 Task/async-await 取代,但理解其原理有助於掌握異步編程本質。關鍵點:
BeginInvoke 創建後台線程EndInvoke 必須調用以獲取結果/異常BeginXxx 線程均為後台線程
