C#異步調用四大方法是什麼呢?C#異步調用四大方法的使用是如何進行的呢?讓咱們首先了解下何時用到C#異步調用:html
.NET Framework
容許您C#異步調用任何方法。定義與您須要調用的方法具備相同簽名的委託;公共語言運行庫將自動爲該委託定義具備適當簽名的 BeginInvoke 和
EndInvoke 方法。編程
BeginInvoke
方法用於啓動C#異步調用。它與您須要異步執行的方法具備相同的參數,只不過還有兩個額外的參數(將在稍後描述)。BeginInvoke
當即返回,不等待C#異步調用完成。BeginInvoke 返回 IasyncResult,可用於監視調用進度。數組
EndInvoke 方法用於檢索C#異步調用結果。調用 BeginInvoke 後可隨時調用
EndInvoke 方法;若是C#異步調用未完成,EndInvoke 將一直阻塞到C#異步調用完成。EndInvoke 的參數包括您須要異步執行的方法的 out
和 ref 參數(在 Visual Basic 中爲 ByRef 和 ByRef)以及由 BeginInvoke 返回的 IAsyncResult。網絡
注意:Visual Studio .NET 中的智能感知功能會顯示 BeginInvoke 和
EndInvoke 的參數。若是您沒有使用 Visual Studio 或相似的工具,或者您使用的是 C# 和 Visual Studio
.NET,請參見異步方法簽名獲取有關運行庫爲這些方法定義的參數的描述。
一.C#異步調用四大方法詳解app
本主題中的代碼演示了四種使用
BeginInvoke 和 EndInvoke 進行C#異步調用的經常使用方法。調用了 BeginInvoke 後,能夠:異步
· 進行某些操做,而後調用 EndInvoke
一直阻塞到調用完成。async
· 使用
IAsyncResult.AsyncWaitHandle 獲取 WaitHandle,使用它的 WaitOne 方法將執行一直阻塞到發出 WaitHandle
信號,而後調用 EndInvoke。異步編程
· 輪詢由 BeginInvoke 返回的
IAsyncResult,肯定C#異步調用什麼時候完成,而後調用 EndInvoke。函數
· 將用於回調方法的委託傳遞給
BeginInvoke。該方法在C#異步調用完成後在 ThreadPool 線程上執行,它能夠調用 EndInvoke。工具
警告:始終在C#異步調用完成後調用 EndInvoke。
測試方法和異步委託
四個示例所有使用同一個長期運行的測試方法
TestMethod。該方法顯示一個代表它已開始處理的控制檯信息,休眠幾秒鐘,而後結束。TestMethod 有一個 out 參數(在 Visual Basic
中爲 ByRef),它演示瞭如何將這些參數添加到 BeginInvoke 和 EndInvoke 的簽名中。您能夠用相似的方式處理 ref 參數(在
Visual Basic 中爲 ByRef)。
下面的代碼示例顯示 TestMethod 以及表明 TestMethod
的委託;若要使用任一示例,請將示例代碼追加到這段代碼中。
注意 爲了簡化這些示例,TestMethod 在獨立於 Main()
的類中聲明。或者,TestMethod 能夠是包含 Main() 的同一類中的 static 方法(在 Visual Basic 中爲 Shared)。
using System; using System.Threading; public class AsyncDemo { // The method to be //executed asynchronously. public string TestMethod(int callDuration, out int threadId) { Console.WriteLine("Test method begins."); Thread.Sleep(callDuration); threadId = AppDomain.GetCurrentThreadId(); return "MyCallTime was" + callDuration.ToString(); } } // The delegate must have //the same signature as the method // you want to call asynchronously. public delegate string AsyncDelegate(int callDuration, out int threadId);
0x01:C#異步調用四大方法之使用
EndInvoke 等待異步調用
異步執行方法的最簡單方式是以 BeginInvoke 開始,對主線程執行一些操做,而後調用
EndInvoke。EndInvoke 直到C#異步調用完成後才返回。這種技術很是適合文件或網絡操做,可是因爲它阻塞
EndInvoke,因此不要從用戶界面的服務線程中使用它。
public class AsyncMain { static void Main(string[] args) { // The asynchronous method // puts the thread id here. int threadId; AsyncDemo ad = new AsyncDemo(); AsyncDelegate dlgt = new AsyncDelegate(ad.TestMethod); IAsyncResult ar = dlgt.BeginInvoke(3000,out threadId, null, null); Thread.Sleep(0); Console.WriteLine("Main thread{0} does some work.", AppDomain.GetCurrentThreadId()); string ret = dlgt.EndInvoke(out threadId, ar); Console.WriteLine("The call executed on thread{0},with return value\"{1}\".",threadId, ret); } }
0x02:C#異步調用四大方法之使用
WaitHandle 等待異步調用
等待 WaitHandle 是一項經常使用的線程同步技術。您可使用由 BeginInvoke 返回的
IAsyncResult 的 AsyncWaitHandle 屬性來獲取 WaitHandle。C#異步調用完成時會發出 WaitHandle
信號,而您能夠經過調用它的 WaitOne 等待它。
若是您使用 WaitHandle,則在C#異步調用完成以後,但在經過調用 EndInvoke
檢索結果以前,能夠執行其餘處理。
public class AsyncMain { static void Main(string[] args) { int threadId; AsyncDemo ad = new AsyncDemo(); AsyncDelegate dlgt = new AsyncDelegate(ad.TestMethod); IAsyncResult ar = dlgt.BeginInvoke(3000,out threadId, null,null); Thread.Sleep(0); Console.WriteLine("Main thread{0} does some work.",AppDomain.GetCurrentThreadId()); string ret = dlgt.EndInvoke(out threadId, ar); Console.WriteLine("The call executed on thread{0},with return value\"{1}\".",threadId, ret); } }
0x03:C#異步調用四大方法之輪詢異步調用完成
您可使用由 BeginInvoke 返回的 IAsyncResult 的 IsCompleted
屬性來發現C#異步調用什麼時候完成。從用戶界面的服務線程中進行C#異步調用時能夠執行此操做。輪詢完成容許用戶界面線程繼續處理用戶輸入。
public class AsyncMain { static void Main(string[] args) { int threadId; AsyncDemo ad = new AsyncDemo(); AsyncDelegate dlgt = new AsyncDelegate(ad.TestMethod); IAsyncResult ar = dlgt.BeginInvoke(3000,out threadId, null,null); while(ar.IsCompleted ==false) { Thread.Sleep(10); } string ret = dlgt.EndInvoke(out threadId, ar); Console.WriteLine("The call executed on thread{0},with return value\"{1}\".",threadId, ret); } }
0x04:C#異步調用四大方法之異步調用完成時執行回調方法
若是啓動異步調用的線程不須要處理調用結果,則能夠在調用完成時執行回調方法。回調方法在
ThreadPool 線程上執行。
要使用回調方法,必須將表明該方法的 AsyncCallback 委託傳遞給
BeginInvoke。也能夠傳遞包含回調方法將要使用的信息的對象。例如,能夠傳遞啓動調用時曾使用的委託,以便回調方法可以調用 EndInvoke。
public class AsyncMain { private static int threadId; static void Main(string[] args) { AsyncDemo ad = new AsyncDemo(); AsyncDelegate dlgt = new AsyncDelegate(ad.TestMethod); IAsyncResult ar = dlgt.BeginInvoke(3000,out threadId,new AsyncCallback(CallbackMethod),dlgt); Console.WriteLine("DIVss Enter to close application."); Console.ReadLine(); } static void CallbackMethod(IAsyncResult ar) { AsyncDelegate dlgt = (AsyncDelegate) string ret = dlgt.EndInvoke(out threadId, ar); Console.WriteLine("The call executed on thread{ 0},with return value\"{1}\".",threadId, ret); } }
二.C#異步調用四大方法的基本內容就向你介紹到這裏,下面看有回調函數的WebRequest和WebResponse的異步操做。
using System; using System.Net; using System.Threading; using System.Text; using System.IO; // RequestState 類用於經過 // 異步調用傳遞數據 public class RequestState { const int BUFFER_SIZE = 1024; public StringBuilder RequestData; public byte[] BufferRead; public HttpWebRequest Request; public Stream ResponseStream; // 建立適當編碼類型的解碼器 public Decoder StreamDecode = Encoding.UTF8.GetDecoder(); public RequestState() { BufferRead = new byte[BUFFER_SIZE]; RequestData = new StringBuilder(""); Request = null; ResponseStream = null; } } // ClientGetAsync 發出異步請求 class ClientGetAsync { public static ManualResetEvent allDone = new ManualResetEvent(false); const int BUFFER_SIZE = 1024; public static void Main(string[] args) { if (args.Length < 1) { showusage(); return; } // 從命令行獲取 URI Uri HttpSite = new Uri(args[0]); // 建立請求對象 HttpWebRequest wreq = (HttpWebRequest)WebRequest.Create(HttpSite); // 建立狀態對象 RequestState rs = new RequestState(); // 將請求添加到狀態,以便它能夠被來回傳遞 rs.Request = wreq; // 發出異步請求 IAsyncResult r = (IAsyncResult)wreq.BeginGetResponse(new AsyncCallback(RespCallback), rs); allDone.WaitOne(); } public static void showusage() { Console.WriteLine("嘗試獲取 (GET) 一個 URL"); Console.WriteLine("\r\n用法::"); Console.WriteLine("ClientGetAsync URL"); Console.WriteLine("示例::"); Console.WriteLine("ClientGetAsyn http://www.microsoft.com/net/"); } private static void RespCallback(IAsyncResult ar) { // 從異步結果獲取 RequestState 對象 RequestState rs = (RequestState)ar.AsyncState; // 從 RequestState 獲取 HttpWebRequest HttpWebRequest req=rs.Request; // 調用 EndGetResponse 生成 HttpWebResponse 對象 // 該對象來自上面發出的請求 HttpWebResponse resp = (HttpWebResponse)req.EndGetResponse(ar); // 既然咱們擁有了響應,就該從 //響應流開始讀取數據了 Stream ResponseStream = resp.GetResponseStream(); // 該讀取操做也使用異步完成,因此咱們 //將要以 RequestState 存儲流 rs.ResponseStream= ResponseStream; // 請注意,rs.BufferRead 被傳入到 BeginRead。 // //這是數據將被讀入的位置。 IAsyncResult iarRead = ResponseStream.BeginRead(rs.BufferRead,0, BUFFER_SIZE, new AsyncCallback(ReadCallBack),rs); } private static void ReadCallBack(IAsyncResult asyncResult) { // 從 asyncresult 獲取 RequestState 對象 RequestState rs = (RequestState)asyncResult.AsyncState; // 取出在 RespCallback 中設置的 ResponseStream Stream responseStream = rs.ResponseStream; // 此時 rs.BufferRead 中應該有一些數據。 //讀取操做將告訴咱們那裏是否有數據 int read =responseStream.EndRead(asyncResult); if (read > 0) { // 準備 Char 數組緩衝區,用於向 Unicode 轉換 Char[] charBuffer = new Char[BUFFER_SIZE]; // 將字節流轉換爲 Char 數組,而後轉換爲字符串 //len 顯示多少字符被轉換爲Unicode int len =rs.StreamDecode.GetChars(rs.BufferRead, 0, read, charBuffer, 0); String str = new String(charBuffer, 0, len); // 將最近讀取的數據追加到 RequestData stringbuilder 對象中, //該對象包含在 RequestState中 rs.RequestData.Append(str); // 如今發出另外一個異步調用,讀取更多的數據 // 請注意,將不斷調用此過程,直到 //responseStream.EndRead 返回-1 IAsyncResult ar = responseStream.BeginRead(rs.BufferRead, 0, BUFFER_SIZE, new AsyncCallback(ReadCallBack), rs); } else { if (rs.RequestData.Length > 1) { // 全部數據都已被讀取,所以將其顯示到控制檯 string strContent; strContent = rs.RequestData.ToString(); Console.WriteLine(strContent); } // 關閉響應流 responseStream.Close(); // 設置 ManualResetEvent,以便主線程能夠退出 allDone.Set(); } return; } }
在這裏有回調函數,且異步回調中又有異步操做。
首先是異步得到ResponseStream,而後異步讀取數據。
這個程序很是經典。從中能夠學到不少東西的。咱們來共同探討。
總結
上面說過,.net framework 能夠異步調用任何方法。因此異步用處普遍。
在.net framework 類庫中也有不少異步調用的方法。通常都是已Begin開頭End結尾構成一對,異步委託方法,外加兩個回調函數和AsyncState參數,組成異步操做的宏觀體現。因此要作異步編程,不要忘了委託delegate、Begin,End,AsyncCallBack委託,AsyncState實例(在回調函數中經過IAsyncResult.AsyncState來強制轉換),IAsycResult(監控異步),就足以理解異步真諦了
資源來自網絡,分別爲:
http://www.cnblogs.com/ericwen/archive/2008/03/12/1101801.html
http://developer.51cto.com/art/200908/145541.htm