異步編程是受公共語言運行庫的許多領域(如遠程處理、ASP.NET 和 Windows 窗體)支持的功能。異步編程是 .NET Framework 中的核心概念。使用 .NET 異步編程,在程序繼續執行的同時對 .NET 類方法進行調用,直到進行指定的回調爲止;或者如果沒有提供回調,則直到對調用的阻塞、輪詢或等待完成爲止。
異步編程是由 .NET Framework 的許多區域支持的功能,這些區域包括:
- 文件 IO、流 IO、套接字 IO
- 網絡:HTTP、TCP
- 遠程處理信道(HTTP、TCP)和代理
- 使用 ASP.NET 創建的 XML Web services
- ASP.NET Web 窗體
- 使用 MessageQueue 類的消息隊列
- 異步委託
.NET Framework 允許異步調用任何方法。定義與需要調用的方法具有相同簽名的委託;公共語言運行庫將自動爲該委託定義具有適當簽名的 BeginInvoke 和 EndInvoke 方法。
- BeginInvoke 方法用於啓動異步調用。它與需要異步執行的方法具有相同的參數,只不過還有兩個額外的參數(將在稍後描述)。BeginInvoke 立即返回,不等待異步調用完成。BeginInvoke 返回 IasyncResult,可用於監視調用進度。
- EndInvoke 方法用於檢索異步調用結果。調用 BeginInvoke 後可隨時調用 EndInvoke 方法;如果異步調用未完成,EndInvoke 將一直阻塞到異步調用完成。EndInvoke 的參數包括需要異步執行的方法的 out 和 ref 參數以及由 BeginInvoke 返回的 IAsyncResult。
調用了 BeginInvoke 後,可以:
- 進行某些操作,然後調用 EndInvoke 一直阻塞到調用完成。
- 使用 IAsyncResult.AsyncWaitHandle 獲取 WaitHandle,使用它的 WaitOne 方法將執行一直阻塞到發出 WaitHandle 信號,然後調用 EndInvoke。
- 輪詢由 BeginInvoke 返回的 IAsyncResult,確定異步調用何時完成,然後調用 EndInvoke。
- 將用於回調方法的委託傳遞給 BeginInvoke。該方法在異步調用完成後在 ThreadPool 線程上執行,它可以調用 EndInvoke。
下面是一個使用委託調用異步方法的例子。實例中首先定義了一個AddDelegate類型委託add,並將方法Add綁定到委託實例上。然後定義了IAsyncResult接口類型實例iAR並調用委託add的BeginInvoke方法用於啓動異步調用。由於異步調用完成時會發出 WaitHandle 信號,因此可以通過iAR.AsyncWaitHandle.WaitOne();來等待它,在這期間主程序可以執行一些其他的任務以達到程序異步執行的效果。最後調用EndInvoke 方法用於檢索異步調用結果。值得注意的是如果異步調用未完成,EndInvoke 將一直阻塞到異步調用完成。
using System.Threading;
//使用委託調用異步方法的例子
namespace DelegateCallAsynchronousMethods
{
class AsyncDelegatesBlocked
{
public static int Add(int op1, int op2, out int result)
{
Thread.Sleep(3000); // Simulating work
return (result = op1 + op2);
}
public delegate int AddDelegate(int op1, int op2,
out int result);//聲明AddDelegate委託
static void Main()
{
int result;
/*定義一個AddDelegate類型委託add,將方法Add綁定到委託實例上*/
AddDelegate add = new AddDelegate(Add);
Console.WriteLine("[Main] Invoking the asynchronous " +
"Add method");
/*BeginInvoke 方法用於啓動異步調用。它與您需要異步執行的方法具有相同的參數,還有兩個額外的參數
*BeginInvoke 立即返回,不等待異步調用完成。BeginInvoke 返回 IasyncResult,可用於監視調用進度。*/
//定義IAsyncResult接口類型實例iAR
//6, 42, out result爲異步執行的方法的參數列表
IAsyncResult iAR = add.BeginInvoke(6, 42, out result,
null, null);
// Here we're simulating doing some work before
// blocking on the Add method's completion.
Console.Write("[Main] Doing other work");
for (int i = 0; i < 10; i++)
{
Thread.Sleep(200);
Console.Write(".");
}
Console.WriteLine(" [Main] Waiting for Add to finish");
/*使用 IAsyncResult.AsyncWaitHandle 獲取 WaitHandle,
* 使用它的 WaitOne 方法將執行一直阻塞到發出 WaitHandle 信號,然後調用 EndInvoke。
* 注意:異步調用完成時會發出 WaitHandle 信號,可以通過WaitOne 來等待它*/
iAR.AsyncWaitHandle.WaitOne();
Console.WriteLine("[Main] Add finished, cleaning up");
/*EndInvoke 方法用於檢索異步調用結果。調用 BeginInvoke 後可隨時調用 EndInvoke 方法;
* 如果異步調用未完成,EndInvoke 將一直阻塞到異步調用完成。
* EndInvoke 的參數包括所需要異步執行的方法的 out 和 ref 參數以及由 BeginInvoke 返回的 IAsyncResult。*/
add.EndInvoke(out result, iAR);
Console.WriteLine("[Main] The result is {0}", result);
Console.ReadLine();
}
};
}