近期項目中使用了不少非同步作業,關於“非同步”做個總結。總結的內容大部分都來自於MSDN,還有一些自己的心得。
關於“非同步”的使用可分為:使用層面和類庫設計層面,細分如下:
一、使用非同步方式調用同步方法(使用層面)。
二、使用 IAsyncResult 調用非同步方法呼叫(使用層面)。
三、基於 IAsyncResult 的非同步設計模式(設計層面)。
四、事件架構非同步模式(設計層面)。
關於上述非同步編程的幾個方面,下面分別做以詳述。
一、使用非同步方式調用同步方法(使用層面)
.NET Framework 允許您非同步呼叫任何方法。為此,應定義與您要調用的方法具有相同簽名的委託;公用語言運行庫會自動使用適當的簽名為該委託定義 BeginInvoke 和 EndInvoke 方法。BeginInvoke 方法可啟動非同步呼叫,EndInvoke 方法檢索非同步呼叫的結果。調用 BeginInvoke 後可隨時調用 EndInvoke 方法;如果非同步呼叫尚未完成,EndInvoke 將一直阻止調用線程,直到非同步呼叫完成後才允許調用線程執行。
該調用方式是使用委託進行非同步呼叫,其實質是:調用“BeginInvoke”方法,公用語言運行庫 (CLR) 將對請求進行排隊並立即返回到調用方。將對來自線程池的線程調用該目標方法。提交請求的原始線程自由地繼續與目標方法並存執行,該目標方法是線上程池線程啟動並執行。
在非同步呼叫啟動後,在等待非同步呼叫結果的時候,可以進行以下四種方法。
· 進行某些操作,然後調用 EndInvoke 一直阻止到調用完成。
using System;using System.Threading;namespace Examples.AdvancedProgramming.AsynchronousOperations{ public class AsyncMain { public static void Main() { // The asynchronous method puts the thread id here. int threadId; // Create an instance of the test class. AsyncDemo ad = new AsyncDemo(); // Create the delegate. AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod); // Initiate the asychronous call. IAsyncResult result = caller.BeginInvoke(3000, out threadId, null, null); Thread.Sleep(0); Console.WriteLine("Main thread {0} does some work.", Thread.CurrentThread.ManagedThreadId); // 調用此方法將會一直等待非同步作業完成,並阻塞當前線程。 string returnValue = caller.EndInvoke(out threadId, result); Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".", threadId, returnValue); } }}
· 進行某些操作,然後使用 IAsyncResult..::.AsyncWaitHandle 屬性擷取 WaitHandle,使用它的 WaitOne 方法(該方法可以設定一個逾時時間)一直阻止執行直到發出 WaitHandle 訊號,然後調用 EndInvoke。
using System;using System.Threading;namespace Examples.AdvancedProgramming.AsynchronousOperations{ public class AsyncMain { static void Main() { // The asynchronous method puts the thread id here. int threadId; // Create an instance of the test class. AsyncDemo ad = new AsyncDemo(); // Create the delegate. AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod); // Initiate the asychronous call. IAsyncResult result = caller.BeginInvoke(3000, out threadId, null, null); Thread.Sleep(0); Console.WriteLine("Main thread {0} does some work.", Thread.CurrentThread.ManagedThreadId); // 調用此方法將會一直等待非同步作業完成,並阻塞當前線程。 result.AsyncWaitHandle.WaitOne(); // Perform additional processing here. // Call EndInvoke to retrieve the results. string returnValue = caller.EndInvoke(out threadId, result); Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".", threadId, returnValue); } }}
· 進行某些操作,然後輪詢由 BeginInvoke 返回的 IAsyncResult,確定非同步呼叫何時完成,然後調用 EndInvoke。
using System;using System.Threading;namespace Examples.AdvancedProgramming.AsynchronousOperations{ public class AsyncMain { static void Main() { // The asynchronous method puts the thread id here. int threadId; // Create an instance of the test class. AsyncDemo ad = new AsyncDemo(); // Create the delegate. AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod); // Initiate the asychronous call. IAsyncResult result = caller.BeginInvoke(3000, out threadId, null, null); // 等待結果返回 while (result.IsCompleted == false) { Thread.Sleep(10); } // Call EndInvoke to retrieve the results. string returnValue = caller.EndInvoke(out threadId, result); Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".", threadId, returnValue); } }}
· 將用於回調方法的委託傳遞給 BeginInvoke。非同步呼叫完成後,將在 ThreadPool 線程上執行該方法。該回調方法將調用 EndInvoke。注意:該回呼函數的執行是在另外一個線程上。
using System;using System.Threading;namespace Examples.AdvancedProgramming.AsynchronousOperations{ public class AsyncMain { // Asynchronous method puts the thread id here. private static int threadId; static void Main() { // Create an instance of the test class. AsyncDemo ad = new AsyncDemo(); // Create the delegate. AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod); // Initiate the asychronous call. Include an AsyncCallback // delegate representing the callback method, and the data // needed to call EndInvoke. IAsyncResult result = caller.BeginInvoke(3000, out threadId, new AsyncCallback(CallbackMethod), caller ); Console.WriteLine("Press Enter to close application."); Console.ReadLine(); } // Callback method must have the same signature as the // AsyncCallback delegate. static void CallbackMethod(IAsyncResult ar) { // Retrieve the delegate. AsyncMethodCaller caller = (AsyncMethodCaller) ar.AsyncState; // Call EndInvoke to retrieve the results. string returnValue = caller.EndInvoke(out threadId, ar); Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".", threadId, returnValue); } }}
二、使用 IAsyncResult 調用非同步方法呼叫(使用層面)
.NET Framework 的許多方面都支援非同步編程功能,這些方麵包括:
· 檔案 IO、流 IO、通訊端 IO。
· 網路。
· 遠端通道(HTTP、TCP)和代理。
· 使用 ASP.NET 建立的 XML Web services。
· ASP.NET Web Form。
· 使用 MessageQueue 類的訊息佇列。
這些已經實現了非同步作業的類或組件,可以直接調用其非同步方法呼叫(以Begin和End開頭)。調用非同步方法呼叫後等待結果可以參考“非同步呼叫同步方法”的處理。
三、基於 IAsyncResult 的非同步設計模式(設計層面)
待續...