.NET之非同步程式設計
同步方法和非同步方法的區別
同步方法呼叫在程式繼續執行之前需要等待同步方法執行完畢返回結果
非同步方法則在被呼叫之後立即返回以便程式在被呼叫方法完成其任務的同時執行其它操作
非同步程式設計概覽
.NET Framework 允許您非同步呼叫任何方法。定義與您需要呼叫的方法具有相同簽名的委託;公共語言執行庫將自動為該委託定義具有適當簽名
的 BeginInvoke 和 EndInvoke 方法。
BeginInvoke 方法用於啟動非同步呼叫。它與您需要非同步執行的方法具有相同的引數,只不過還有兩個額外的引數(將在稍後描述)。
BeginInvoke 立即返回,不等待非同步呼叫完成。
BeginInvoke 返回 IasyncResult,可用於監視呼叫進度。
EndInvoke 方法用於檢索非同步呼叫結果。呼叫 BeginInvoke 後可隨時呼叫 EndInvoke 方法;如果非同步呼叫未完成,EndInvoke 將一直阻塞到
非同步呼叫完成。EndInvoke 的引數包括您需要非同步執行的方法的 out 和 ref 引數(在 Visual Basic 中為
BeginInvoke 返回的 IAsyncResult。
四種使用 BeginInvoke 和 EndInvoke 進行非同步呼叫的常用方法。呼叫了 BeginInvoke 後,可以:
1.進行某些操作,然後呼叫 EndInvoke 一直阻塞到呼叫完成。
2.使用 IAsyncResult.AsyncWaitHandle 獲取 WaitHandle,使用它的 WaitOne 方法將執行一直阻塞到發出 WaitHandle 訊號,然後呼叫
EndInvoke。這裡主要是主程式等待非同步方法,等待非同步方法的結果。
3.輪詢由 BeginInvoke 返回的 IAsyncResult,IAsyncResult.IsCompeted確定非同步呼叫何時完成,然後呼叫 EndInvoke。此處理個人認為與
相同。
4.將用於回撥方法的委託傳遞給 BeginInvoke。該方法在非同步呼叫完成後在 ThreadPool 執行緒上執行,它可以呼叫 EndInvoke。這是在強制裝
換回撥函式裡面IAsyncResult.AsyncState(BeginInvoke方法的最後一個引數)成委託,然後用委託執行EndInvoke。
警告 始終在非同步呼叫完成後呼叫 EndInvoke。
以上有不理解的稍後可以再理解。
例子
1)先來個簡單的沒有回撥函式的非同步方法例子
請再執行程式的時候,仔細看註釋,對理解很有幫助。還有,若將註釋的中的兩個方法都同步,你會發現非同步執行的速度優越性。
using System;
namespace ConsoleApplication1
{
class Class1
{
//宣告委託
public delegate void AsyncEventHandler();
//非同步方法
void Event1()
{
Console.WriteLine("Event1 Start");
System.Threading.Thread.Sleep(4000);
Console.WriteLine("Event1 End");
}
// 同步方法
void Event2()
{
Console.WriteLine("Event2 Start");
int i=1;
while(i<1000)
{
i=i+1;
Console.WriteLine("Event2 "+i.ToString());
}
Console.WriteLine("Event2 End");
}
[STAThread]
static void Main(string[] args)
{
long start=0;
long end=0;
Class1 c = new Class1();
Console.WriteLine("ready");
start=DateTime.Now.Ticks;
//例項委託
AsyncEventHandler asy = new AsyncEventHandler(c.Event1);
//非同步呼叫開始,沒有回撥函式和AsyncState,都為null
IAsyncResult ia = asy.BeginInvoke(null, null);
//同步開始,
c.Event2();
//非同步結束,若沒有結束,一直阻塞到呼叫完成,在此返回該函式的return,若有返回值。
asy.EndInvoke(ia);
//都同步的情況。
//c.Event1();
//c.Event2();
end =DateTime.Now.Ticks;
Console.WriteLine("時間刻度差="+ Convert.ToString(end-start) );
Console.ReadLine();
}
}
}
2)下面看有回撥函式的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);
// 將 ManualResetEvent 設定為 Wait,
// 以便在呼叫回撥前,應用程式不退出
allDone.WaitOne();
}
public static void showusage()
{
Console.WriteLine("嘗試獲取 (GET) 一個 URL");
Console.WriteLine("\r\n用法::");
Console.WriteLine("ClientGetAsync URL");
Console.WriteLine("示例::");
Console.WriteLine("ClientGetAsync 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(監控非同步),就足以理解非同步真諦了。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-624340/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- python 網路程式設計----非阻塞或非同步程式設計Python程式設計非同步
- [譯] 非同步程式設計:阻塞與非阻塞非同步程式設計
- Socket程式設計中的同步、非同步、阻塞和非阻塞(轉)程式設計非同步
- JS非同步程式設計之PromiseJS非同步程式設計Promise
- JS非同步程式設計之GeneratorJS非同步程式設計
- JS非同步程式設計之callbackJS非同步程式設計
- python之非同步程式設計Python非同步程式設計
- 非同步程式設計:.NET 4.5 基於任務的非同步程式設計模型(TAP)非同步程式設計模型
- Flutter開發之非同步程式設計Flutter非同步程式設計
- dart基礎之非同步程式設計Dart非同步程式設計
- 2、Dart:非同步程式設計之Futures;Dart非同步程式設計
- 非同步程式設計之使用yield from非同步程式設計
- 【進階之路】併發程式設計(三)-非阻塞同步機制程式設計
- .NET 中的 async/await 非同步程式設計AI非同步程式設計
- 一文徹底搞定(阻塞/非阻塞/同步/非同步)網路IO、併發程式設計模型、非同步程式設計模型的愛恨情仇非同步程式設計模型
- 程式設計師的“非程式設計師”之路程式設計師
- .NET非同步程式設計:IO完成埠與BeginRead非同步程式設計
- 非同步程式設計非同步程式設計
- JS非同步程式設計之async&awaitJS非同步程式設計AI
- JavaScript 單執行緒之非同步程式設計JavaScript執行緒非同步程式設計
- python非同步程式設計之asyncio初識Python非同步程式設計
- dart系列之:dart中的非同步程式設計Dart非同步程式設計
- C#非同步程式設計之淺談TaskC#非同步程式設計
- Java 網路程式設計 —— 非阻塞式程式設計Java程式設計
- .net 溫故知新:【5】非同步程式設計 async await非同步程式設計AI
- 對 ASP.NET 非同步程式設計的一點理解ASP.NET非同步程式設計
- .NET多執行緒程式設計(4):執行緒池和非同步程式設計 (轉)執行緒程式設計非同步
- linux非阻塞式socket程式設計之select()用法Linux程式設計
- 非同步程式設計:基於事件的非同步程式設計模式(EAP)非同步程式設計事件設計模式
- Java 非同步程式設計之:notify 和 wait 用法Java非同步程式設計AI
- Java多執行緒程式設計之同步器Java執行緒程式設計
- Node.js 非同步程式設計之 Callback介紹Node.js非同步程式設計
- Dart 非同步程式設計Dart非同步程式設計
- php非同步程式設計PHP非同步程式設計
- asyncio 非同步程式設計非同步程式設計
- js 非同步程式設計JS非同步程式設計
- 非同步程式設計---Promise非同步程式設計Promise
- Javascript 非同步程式設計JavaScript非同步程式設計