從.NET 4.5開始,支持的三種異步編程模式:
•基于事件的異步編程設(shè)計(jì)模式 (EAP,Event-based Asynchronous Pattern)
•異步編程模型(APM,Asynchronous Programming Model)
•基于任務(wù)的編程模型(TAP,Task-based Asynchronous Pattern)
基于任務(wù)的異步模式 (TAP) 是基于 System.Threading.Tasks 命名空間的 Task 和 TaskTResult>,用于表示任意異步操作。 TAP 是新開發(fā)的建議異步設(shè)計(jì)模式,之后再討論。
先總結(jié)一下舊有的2種模式:EAP、APM。
從以下幾個方面,看這2種異步編程方式的異同:
•命名、參數(shù)、返回值
•典型應(yīng)用
•捕獲異常
•狀態(tài)
•取消操作
•進(jìn)度報告
EAP
命名、參數(shù)、返回值
EAP的編程模式的代碼命名有以下特點(diǎn):
•將有一個或多個名為 “[方法名稱]Async” 的方法。這些方法可能會創(chuàng)建同步版本的鏡像,這些同步版本會在當(dāng)前線程上執(zhí)行相同的操作。
•該類還可能有一個 “[方法名稱]Completed” 事件,監(jiān)聽異步方法的結(jié)果。
•它可能會有一個 “[方法名稱]AsyncCancel”(或只是 CancelAsync)方法,用于取消正在進(jìn)行的異步操作。
參數(shù)和返回值都沒有特殊規(guī)定,按照業(yè)務(wù)需求而定
典型應(yīng)用
以請求一個Url為例
復(fù)制代碼 代碼如下:
public class EAP_Typical
{
public static void AsyncRun()
{
Utility.Log("AsyncRun:start");
//測試網(wǎng)址
string url = http://sports.163.com/nba/;
using (WebClient webClient = new WebClient())
{
//獲取完成情況
webClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(webClient_DownloadStringCompleted);
webClient.DownloadStringAsync(new Uri(url));
Utility.Log("AsyncRun:download_start");
}
}
static void webClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
string log = "AsyncRun:download_completed";
//獲取返回結(jié)果
log += "|result_size=" + Utility.GetStrLen(e.Result);
Utility.Log(log);
}
}
捕獲異常
異常信息一般在Completed的事件參數(shù)中傳遞的。緊接上面的例子,如果需要獲取返回的異常信息,則需要改寫一下DownloadStringComleted的方法。
復(fù)制代碼 代碼如下:
static void webClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
string log = "AsyncRun:download_completed";
if (e.Error != null) //可見,在事件的參數(shù)傳輸異常信息
{
//出現(xiàn)異常,就記錄異常
log += "|error=" + e.Error.Message;
}
else
{
//沒有出現(xiàn)異常,則記錄結(jié)果
log += "|result_size=" + Utility.GetStrLen(e.Result);
}
Utility.Log(log);
}
狀態(tài)
EAP本身并沒有維護(hù)狀態(tài),如果需要的話,應(yīng)該設(shè)置不同的時間響應(yīng)不同的狀態(tài)改變;
假設(shè)剛才的DownloadStringAsync,需要增加多幾個狀態(tài)值,可以考慮增加多幾個事件。
如
Event DownloadStringStarted(響應(yīng)下載剛開始)
Event DownloadStringPending(響應(yīng)下載阻塞中)
Event DownloadStringCancel(響應(yīng)下載取消時)
等等。
取消操作
按命名規(guī)范,如果操作對應(yīng)有“[方法名稱]AsyncCancel”(或只是 CancelAsync)方法,則支持取消操作。
取消的狀態(tài)捕獲,還是以剛才的下載Url輸出html為例,還是在DownloadStringCompleted 獲取取消與否的狀態(tài)。DownloadStringCompletedEventArgs. Cancelled
注意的是,如果用戶執(zhí)行了CancelAsync后,在DownloadStringCompletedEventArgs.Error就會獲取到對應(yīng)的異常,此時不要再取DownloadStringCompletedEventArgs.Result。
進(jìn)度報告
EAP沒有硬性規(guī)定說要支持進(jìn)度報告,但可以很順其自然地通過時間響應(yīng)進(jìn)度變化。
以當(dāng)前例子,WebClient 就提供了DownloadProgressChanged 做進(jìn)度變化的響應(yīng)事件。
APM
命名、參數(shù)、返回值
APM的編程模式的代碼命名有以下特點(diǎn):
•使用 IAsyncResult 設(shè)計(jì)模式的異步操作是通過名為[Begin操作名稱] 和 [End操作名稱] 的兩個方法來實(shí)現(xiàn)的,這兩個方法分別開始和結(jié)束異步操作 操作名稱。 例如,F(xiàn)ileStream 類提供 BeginRead 和 EndRead 方法來從文件異步讀取字節(jié)。 這兩個方法實(shí)現(xiàn)了 Read 方法的異步版本。
•在調(diào)用 [Begin操作名稱] 后,應(yīng)用程序可以繼續(xù)在調(diào)用線程上執(zhí)行指令,同時異步操作在另一個線程上執(zhí)行。 每次調(diào)用 [Begin操作名稱] 時,應(yīng)用程序還應(yīng)調(diào)用 [End操作名稱] 來獲取操作的結(jié)果。
典型應(yīng)用
以請求一個Url為例
復(fù)制代碼 代碼如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
namespace AsyncTest1.APM
{
public class APMTestRun1
{
public static void AsyncRun()
{
Utility.Log("APMAsyncRun:start");
//測試網(wǎng)址
string url = "http://sports.163.com/nba/";
HttpWebRequest webRequest = HttpWebRequest.Create(url) as HttpWebRequest;
webRequest.BeginGetResponse(Callback, webRequest);
Utility.Log("AsyncRun:download_start");
}
private static void Callback(IAsyncResult ar)
{
var source = ar.AsyncState as HttpWebRequest;
var response = source.EndGetResponse(ar);
using (var stream = response.GetResponseStream())
{
using (var reader = new StreamReader(stream))
{
string content = reader.ReadToEnd();
Utility.Log("AsyncRun:result_size=" + Utility.GetStrLen(content));
}
}
}
}
}
委托的異步調(diào)用也用的是APM模式,這個方式的強(qiáng)大之處,在于可以使任何方法編程異步調(diào)用。
復(fù)制代碼 代碼如下:
/// summary>
/// 一個耗時的方法
/// /summary>
private static void CaluateManyNumber() {
for (int i = 0; i 10; i++)
{
Thread.Sleep(100);
Console.WriteLine("loop==>"+i.ToString());
}
}
/// summary>
/// 委托,讓耗時方法可以異步執(zhí)行
/// /summary>
public static void AsyncDelegate() {
//委托簡單的包裝了一下方法
Action action = CaluateManyNumber;
action.BeginInvoke(DelegateCallback, null);
Console.WriteLine("action begin");
}
/// summary>
/// 異步回調(diào)
/// /summary>
/// param name="ar">/param>
private static void DelegateCallback(IAsyncResult ar) {
AsyncResult asyncResult = ar as AsyncResult;
var delegateSource = asyncResult.AsyncDelegate as Action;
delegateSource.EndInvoke(ar);
Console.WriteLine("action end");
}
捕獲異常
異常信息要在[End操作名稱]中獲取。
復(fù)制代碼 代碼如下:
private static void Callback(IAsyncResult ar)
{
var source = ar.AsyncState as HttpWebRequest;
WebResponse response = null;
try
{
response = source.EndGetResponse(ar);
}
catch (Exception ex) {
Utility.Log("error:" + ex.Message);
response = null;
}
if (response != null)
{
using (var stream = response.GetResponseStream())
{
using (var reader = new StreamReader(stream))
{
string content = reader.ReadToEnd();
Utility.Log("AsyncRun:result_size=" + Utility.GetStrLen(content));
}
}
}
}
狀態(tài)和取消操作、進(jìn)度報告
APM模式本身不支持狀態(tài)多樣化和取消操作、進(jìn)度報告。
您可能感興趣的文章:- 深入分析C#異步編程詳解
- 高效的.Net UDP異步編程實(shí)現(xiàn)分析
- .net4.5使用async和await異步編程實(shí)例