在上兩個專題中我為大家介紹.NET 1.0中的APM和.NET 2.0中的EAP,在使用前面兩種模式進行異步編程的時候,大家多多少少肯定會感覺到實現起來比較麻煩, 首先——基於任務的異步模式,該模式主要使用System.Threading.Tasks.Task和Task<T>類來完成異步編程,相對於前面兩種異步模式來講,TAP使異步編程模式更加簡單(因為這裡我們只需要關注Task這個類的使用),同時TAP也是微軟推薦使用的異步編程模式,下面就具體為大家分享下本專題的內容.
基於任務的異步模式(Task-based Asynchronous Pattern,TAP)之所以被微軟所推薦,主要就它使用簡單,基於任務的異步模式使用單個方法來表示異步操作的開始和完成,然而異步編程模型(APM)卻要求BeginXxx和EndXxx兩個方法來分別表示異步操作的開始和完成(這樣使用起來就復雜了),然而,基於事件的異步模式(EAP)要求具有Async後綴的方法和一個或多個事件、事件處理程序和事件參數。看到這裡,是不是大家都有這樣一個疑問的——我們怎樣區分.NET類庫中的類實現了基於任務的異步模式呢? 這個識別方法很簡單,當看到類中存在TaskAsync為後綴的方法時就代表該類實現了TAP, 和的功能,但是這兩個實現都不像EAP中實現的那麼復雜,因為如果我們要自己實現EAP的類,我們需要定義多個事件和事件處理程序的委托類型和事件的參數(具體可以查看上一專題中的BackgroundWorker剖析部分),但是在TAP實現中,我們只需要通過向異步方法傳入CancellationToken 參數,因為在異步方法內部會對這個參數的IsCancellationRequested屬性進行監控,當異步方法收到一個取消請求時,異步方法將會退出執行(具體這點可以使用反射工具查看WebClient的DownloadDataTaskAsync方法,同時也可以參考我後面部分自己實現基於任務的異步模式的異步方法。),在TAP中,我們可以通過IProgress<T>接口來實現進度報告的功能,具體實現可以參考我後面的程序部分。
看完上面的介紹,我們是不是很迫不及待想知道如何自己實現一個基於任務的異步模式的異步方法的,並且希望只需要這個方法就可以完成異步操作的取消和進度報告的功能的(因為EAP中需要實現其他的事件和定義事件參數類型,這樣的實現未免過於復雜),下面就基於上專題中實現的程序用基於任務的異步模式來完成下。下面就讓我們實現自己的異步方法(亮點為只需要一個方法就可以完成進度報告和異步操作取消的功能):
DownLoadFile( url, CancellationToken ct, IProgress<>= = = bufferSize = [] bufferBytes = = (DownloadSize != == readSize = ( (ct.IsCancellationRequested == =>.btnStart.Enabled = .btnPause.Enabled = = responseStream.Read(bufferBytes, (readSize > += percentComplete = ()(()DownloadSize / ()totalSize * =>.btnStart.Enabled = .btnPause.Enabled = ex.Handle(e => e
這樣只需要上面的一個方法,我們就可以完成上一專題中文件下載的程序,我們只需要在下載按鈕的事件處理程序調用該方法和在暫停按鈕的事件處理程序調用CancellationTokenSource.Cancel方法即可,具體代碼為:
btnStart_Click(= .btnStart.Enabled = .btnPause.Enabled = sc == = Task(() => DownLoadFile(txbUrl.Text.Trim(), ct, Progress<>(p => SendOrPostCallback((result)=>progressBar1.Value=( btnPause_Click(
下面看看基於任務的異步模式的實現效果如何的,運行結果:
點擊確定按鈕之後,Download按鈕會重新變成可用,此時我們可以繼續點擊Download按鈕來下載進行下載,下載完成之後會下載完成彈出框,運行結果如下:
從上面的程序代碼我們可以清楚的發現——基於任務的異步模式確實比前面的兩種異步模式更加簡單使用,所以,從.NET Framework 4.0開始,微軟推薦使用TAP來實現異步編程,這裡就涉及之前用APM或EAP實現的程序如何遷移到用TAP實現的問題的,同時.NET Framwwork對他們之間的轉換了也做了很好的支持。
在System.Threading.Tasks命名空間中,有一個TaskFactory(任務工程)類,我們正可以利用該類的FromAsync方法來實現將APM轉換為TAP,下面就用基於任務的異步模式來實現在異步編程模型博文中例子。
使用APM實現異步請求 = WebRequest.Create(=>= = + + (webResponse != 使用FromAsync方法將APM轉換為TAP = WebRequest.Create(<WebResponse>(webRq.BeginGetResponse, webRq.EndGetResponse, =>= = + (ex.GetBaseException() + (webResponse !=
上面代碼演示了使用APM的原始實現方式以及如何使用FromAsync方法把APM的實現方式轉換為TAP的實現方法,把這兩種方式放在一起,一是可以幫助大家做一個對比,使大家更容易明白APM與TAP的轉換,二是大家也可以通過上面的對比明白TAP與APM的區別。
處理APM可以升級為用TAP來實現外,對於EAP,我們同樣可以對其轉換為TAP的方式,下面代碼演示了如何將EAP轉換為TAP的實現方式:
將EAP轉換為TAP的實現方式 WebClient webClient = TaskCompletionSource<> tcs = TaskCompletionSource<> webClient.DownloadStringCompleted += (sender, e) => (e.Error != tcs.Task.ContinueWith(t => + webClient.DownloadStringAsync( Uri(
本專題關於TAP的內容就介紹到這裡了,本專題主要以實現一個文件下載程序要講述基於任務的異步模式所帶來的簡便,這個也是.NET 4.0中提出TAP的原因所在吧,最後介紹了TAP與APM和EAP模式之間的轉化,通過這部分大家可以清楚知道以前的異步實現如何向新的異步模式的遷移,以及從他們的轉換實現代碼中也可以比較他們之間的不同。然而在.NET 4.5中,微軟對異步編程又做了更好的支持——提供了async和await兩個關鍵字,這兩個關鍵字使我們異步編程如同步編程一樣的簡單,徹底改變了實現異步編程所面臨的委托回調,跨線程訪問控件等問題,具體這部分內容,我將在下個專題中為大家介紹。
本專題源碼下載:http://files.cnblogs.com/zhili/TaskbasedAsynchronousPattern(TAP).zip