天天看點

[你必須知道的異步程式設計]——異步程式設計模型(APM)

本專題概要:

引言

你知道APM嗎?

你想知道如何使用異步程式設計模型編寫代碼嗎?

使用委托也可以實作異步程式設計,你知道否?

小結

一、引言

  在開始講解APM之前,我想先分享一下Visual Studio 版本、C# 版本和.NET 版本的一個對應關系。之是以在這裡分享這個對應關系,是因為在C#基礎知識系列的文章釋出之後,有些初學者對.NET版本和C#語言特性之間的對應關系有點不清楚,有時候會弄混淆了。并且通過這個對應關系,也可以幫助大家對C#和.NET 類庫有個全面的把控,可以幫助大家理清楚C#和.NET 類庫中各個知識點,使他們可以對号入坐。具體他們的之間對應關系見下表:

C# 版本

.NET Framework版本

Visual Studio版本

釋出日期

特性

C# 1.0

.NET Framework 1.0

Visual Studio .NET 2002

2002.1

<a href="http://www.cnblogs.com/zhili/archive/2012/10/25/DeepDelegate.html" target="_blank">委托</a>

<a href="http://www.cnblogs.com/zhili/archive/2012/10/27/Event.html" target="_blank">事件</a>

APM

C# 1.1

.NET Framework 1.1

Visual Studio .NET 2003

2003.4

C# 2.0

.NET Framework 2.0

Visual Studio 2005(開始命名為Visual Studio)

2005.11

<a href="http://learninghard.blog.51cto.com/6146675/1053386" target="_blank">泛型</a>

<a href="http://learninghard.blog.51cto.com/6146675/1076169" target="_blank">匿名方法</a>

<a href="http://learninghard.blog.51cto.com/6146675/1076730" target="_blank">疊代器</a>

<a href="http://learninghard.blog.51cto.com/6146675/1067849" target="_blank">可空類型</a>

C# 3.0

.NET Framework 3.0

.NET Framework 3.5

Visual Studio 2008

2007.11

<a href="http://learninghard.blog.51cto.com/6146675/1085243" target="_blank">隐式類型的部變量</a>

<a href="http://learninghard.blog.51cto.com/6146675/1085243" target="_blank">對象集合初始化</a>

<a href="http://learninghard.blog.51cto.com/6146675/1085243" target="_blank">自動實作屬性</a>

<a href="http://learninghard.blog.51cto.com/6146675/1085243" target="_blank">匿名類型</a>

<a href="http://learninghard.blog.51cto.com/6146675/1092482">擴充方法</a>

<a href="http://learninghard.blog.51cto.com/6146675/1087512" target="_blank">查詢表達式</a>

<a href="http://learninghard.blog.51cto.com/6146675/1087512" target="_blank">Lambda表達式</a>

<a href="http://learninghard.blog.51cto.com/6146675/1087512" target="_blank">表達式樹</a>

<a href="http://msdn.microsoft.com/zh-cn/library/wa80x488(v=vs.90).aspx" target="_blank">分部類和方法</a>

<a href="http://learninghard.blog.51cto.com/6146675/1097866" target="_blank">Linq</a>

C# 4.0

.NET Framework 4.0

Visual Studio 2010

2010.4

<a href="http://learninghard.blog.51cto.com/6146675/1110708" target="_blank">動态綁定</a>

<a href="http://msdn.microsoft.com/zh-cn/library/dd264739(v=vs.100).aspx" target="_blank">命名和可選參數</a>

<a href="http://learninghard.blog.51cto.com/6146675/1058126" target="_blank">泛型的協變和逆變</a>

<a href="http://learninghard.blog.51cto.com/6146675/1127124" target="_blank">互操作性</a>

C# 5.0

.NET Framework 4.5

Visual Studio 2012

2012.8

異步和等待(async和await)

調用方資訊(Caller Information)

二、你知道APM嗎?

  APM即異步程式設計模型的簡寫(Asynchronous Programming Model),大家在寫代碼的時候或者檢視.NET 的類庫的時候肯定會經常看到和使用以BeginXXX和EndXXX類似的方法,其實你在使用這些方法的時候,你就再使用異步程式設計模型來編寫程式。異步編寫模型是一種模式,該模式允許用更少的線程去做更多的操作,.NET Framework很多類也實作了該模式,同時我們也可以自定義類來實作該模式,(也就是在自定義的類中實作傳回類型為IAsyncResult接口的BeginXXX方法和EndXXX方法),另外委托類型也定義了BeginInvoke和EndInvoke方法,并且我們使用WSDL.exe和SvcUtil.exe工具來生成Web服務的代理類型時,也會生成使用了APM的BeginXxx和EndXxx方法。下面就具體就拿FileStream類的BeginRead和EndRead方法來介紹下下異步程式設計模型的實作。

BeginXxx方法——開始執行異步操作介紹

當需要讀取檔案中的内容時,我們通常會采用FileStream的同步方法Read來讀取,該同步方法的定義為:

1

2

3

4

5

<code>// 從檔案流中讀取位元組塊并将該資料寫入給定的位元組數組中</code>

<code>// array代表把讀取的位元組塊寫入的緩存區</code>

<code>// offset代表array的位元組偏量,将在此處讀取位元組</code>

<code>// count 代表最多讀取的位元組數</code>

<code>public</code> <code>override</code> <code>int</code> <code>Read(</code><code>byte</code><code>[] array, </code><code>int</code> <code>offset, </code><code>int</code> <code>count )</code>

   該同步方法會堵塞執行的線程,當一個WinForm程式需要實作讀取一個大檔案的内容然後把内容顯示在界面時,如果我們調用該方法去讀取檔案的内容時,此時Read方法會堵塞UI線程,在讀取檔案内容沒有完成之前,使用者不能對窗體進行任何的操作,包括關閉應用程式,此時使用者看到的該窗體會出現無法響應,這樣就給使用者帶來不好一個使用者體驗,從使用者角度來看是使用者體驗不好,此時我們自己解決問題的思路肯定是——能不能讓讀取檔案操作在另外一個線程中執行,這樣就不會堵塞UI線程,這時候UI線程繼續做屬于自己的事情,即響應使用者的操作。不錯,微軟也肯定也想到了這個解決方案的,并且在實際操作中也是這麼做的,即通過BeginRead方法來實作異步程式設計,使讀取操作不再堵塞UI線程。BeginRead方法代表異步執行Read操作,并傳回實作IAsyncResult接口的對象,該對象存儲着異步操作的資訊,下面就看下BeginRead方法的定義,看看與同步Read的方法差別在哪裡的.

6

<code>// 開始異步讀操作</code>

<code>// 前面的3個參數和同步方法代表的意思一樣,這裡就不說了,可以看到這裡多出了2個參數</code>

<code>// userCallback代表當異步IO操作完成時,你希望由一個線程池線程執行的方法,該方法必須比對AsyncCallback委托</code>

<code>// stateObject代表你希望轉發給回調方法的一個對象的引用,在回調方法中,可以查詢IAsyncResult接口的AsyncState屬性來通路該對象</code>

<code>public</code> <code>override</code> <code>IAsyncResult BeginRead(</code><code>byte</code><code>[] array, </code><code>int</code> <code>offset, </code><code>int</code> <code>numBytes, AsyncCallback userCallback, Object stateObject</code>

<code>)</code>

從上面的代碼中可以看出異步方法和同步方法的差別,如果你在使用該異步方法時,不希望異步操作完成後調用任何代碼,你可以把userCallback參數設定為null。該異步方法子是以不會堵塞UI線程是因為調用該方法後,該方法會立即把控制權傳回給調用線程(如果是UI線程來調用該方法時,即傳回給UI線程),然而同步卻不是這樣,同步方法是等該操作完成之後傳回讀取的内容之後才傳回給調用線程,進而導緻在操作完成之前調用線程就一直等待狀态。

EndXxx方法——結束異步操作介紹

  前面介紹完了BeginXxx方法,我們看到所有BeginXxx方法傳回的都是實作了IAsyncResult接口的一個對象,并不是對應的同步方法所要得到的結果的。此時我們需要調用對應的EndXxx方法來結束異步操作,并向該方法傳遞IAsyncResult對象,EndXxx方法的傳回類型就是和同步方法一樣的。例如,FileStream的EndRead方法傳回一個Int32來代表從檔案流中實際讀取的位元組數。

對于通路異步操作的結果,APM提供了四種方式供開發人員選擇:

在調用BeginXxx方法的線程上調用EndXxx方法來得到異步操作的結果,但是這種方式會阻塞調用線程,知道操作完成之後調用線程才繼續運作

查詢IAsyncResult的AsyncWaitHandle屬性,進而得到WaitHandle,然後再調用它的WaitOne方法來使一個線程阻塞并等待操作完成再調用EndXxx方法來獲得操作的結果。

循環查詢IAsyncResult的IsComplete屬性,操作完成後再調用EndXxx方法來獲得操作傳回的結果。

使用 AsyncCallback委托來指定操作完成時要調用的方法,在操作完成後調用的方法中調用EndXxx操作來獲得異步操作的結果。

  在上面的4種方式中,第4種方式是APM的首選方式,因為此時不會阻塞執行BeginXxx方法的線程,然而其他三種都會阻塞調用線程,相當于效果和使用同步方法是一樣,個人感覺根本失去了異步程式設計的特點,是以其他三種方式可以簡單了解下,在實際異步程式設計中都是使用委托的方式。

  通過上面的介紹,大家應該對異步程式設計模型有了進一步的了解了吧,要識别某個類是否實作了異步程式設計模型,隻需要看是不是有BeginXxx方法(當然傳回類型需要是IAsyncResult)和EndXxx方法。其實異步程式設計模型這個模式,就是微軟利用委托和線程池幫助我們實作的一個模式(該模式利用一個線程池線程去執行一個操作,在FileStream類BeginRead方法中就是執行一個讀取檔案操作,該線程池線程會立即将控制權傳回給調用線程,此時線程池線程在背景進行這個異步操作;異步操作完成之後,通過回調函數來擷取異步操作傳回的結果。此時就是利用委托的機制。是以說異步程式設計模式時利用委托和線程池線程搞出來的模式,包括後面的基于事件的異步程式設計和基于任務的異步程式設計,還有C# 5中的async和await關鍵字,都是利用這委托和線程池搞出來的。他們的本質其實都是一樣的,隻是後面提出來的使異步程式設計更加簡單罷了。)

既然這裡講到了FileStream對象,這裡就提出一個關于該類值得注意的地方的:

FileStream對象預設情況下是同步打開作業系統句柄,當我們建立一個FileStream對象沒有為其指定FileOptions.Asynchronous參數或者沒有顯示指定useAsync為true時,Windows 作業系統會以同步的方法執行所有的檔案操作,即使此時你還是可以調用BeginRead方法。但是這樣對于你的應用程式,操作隻是表面上是異步執行的,但FileStream類在内部會用另一個線程模拟異步行為。

同樣道理,當建立的FileStream對象指定了FileOptions.Asynchronous參數時,然後我們仍然可以調用Read同步方法,此時在内部,FileStream類會開始一個異步操作,并立即使調用線程進入睡眠狀态,知道操作完成才會喚醒,通過這樣來模拟同步行為。是以在使用FileStream對象時,需要先決定是同步執行還是異步執行。并顯示地指定FileOptions.Asynchronous參數或useAsync參數。

三、你想知道如何使用異步程式設計模型編寫代碼嗎?

  介紹了這麼久的異步程式設計模型,大家肯定很迫不及待地想使用異步程式設計模型來改寫自己的同步應用程式或者實作一個異步的應用程式。下面就通過一個例子來示範如何使用APM來現異步程式設計(該程式也實作了一個同步方法,為了讓大家更好地體會同步線程和異步線程的差別,本程式的實作是一個控制台程式,大家也可以很好地一直與WinForm應用程式和WPF程式):

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

<code>#region use APM to download file asynchronously</code>

<code>        </code><code>private</code> <code>static</code> <code>void</code> <code>DownloadFileAsync(</code><code>string</code> <code>url)</code>

<code>        </code><code>{</code>

<code>            </code><code>try</code>

<code>            </code><code>{</code>

<code>                </code><code>// Initialize an HttpWebRequest object</code>

<code>                </code><code>HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(url);</code>

<code>                </code><code>// Create an instance of the RequestState and assign HttpWebRequest instance to its request field.</code>

<code>                </code><code>RequestState requestState = </code><code>new</code> <code>RequestState();</code>

<code>                </code><code>requestState.request = myHttpWebRequest;</code>

<code>                </code><code>myHttpWebRequest.BeginGetResponse(</code><code>new</code> <code>AsyncCallback(ResponseCallback), requestState);</code>

<code>            </code><code>}</code>

<code>            </code><code>catch</code> <code>(Exception e)</code>

<code>                </code><code>Console.WriteLine(</code><code>"Error Message is:{0}"</code><code>,e.Message);</code>

<code>        </code><code>}</code>

<code>        </code><code>// The following method is called when each asynchronous operation completes.</code>

<code>        </code><code>private</code> <code>static</code> <code>void</code> <code>ResponseCallback(IAsyncResult callbackresult)</code>

<code>            </code><code>// Get RequestState object</code>

<code>            </code><code>RequestState myRequestState = (RequestState)callbackresult.AsyncState;</code>

<code>            </code><code>HttpWebRequest myHttpRequest = myRequestState.request;</code>

<code>            </code><code>// End an Asynchronous request to the Internet resource</code>

<code>            </code><code>myRequestState.response = (HttpWebResponse)myHttpRequest.EndGetResponse(callbackresult);</code>

<code>                                                                                      </code> 

<code>            </code><code>// Get Response Stream from Server</code>

<code>            </code><code>Stream responseStream = myRequestState.response.GetResponseStream();</code>

<code>            </code><code>myRequestState.streamResponse = responseStream;</code>

<code>            </code><code>IAsyncResult asynchronousRead = responseStream.BeginRead(myRequestState.BufferRead, 0, myRequestState.BufferRead.Length, ReadCallBack, myRequestState);     </code>

<code>        </code><code>// Write bytes to FileStream</code>

<code>        </code><code>private</code> <code>static</code> <code>void</code> <code>ReadCallBack(IAsyncResult asyncResult)</code>

<code>                </code><code>// Get RequestState object</code>

<code>                </code><code>RequestState myRequestState = (RequestState)asyncResult.AsyncState;</code>

<code>                </code><code>// Get Response Stream from Server</code>

<code>                </code><code>Stream responserStream = myRequestState.streamResponse;</code>

<code>                </code><code>//</code>

<code>                </code><code>int</code> <code>readSize = responserStream.EndRead(asyncResult);</code>

<code>                </code><code>if</code> <code>(readSize &gt; 0)</code>

<code>                </code><code>{</code>

<code>                    </code><code>myRequestState.filestream.Write(myRequestState.BufferRead, 0, readSize);</code>

<code>                    </code><code>responserStream.BeginRead(myRequestState.BufferRead, 0, myRequestState.BufferRead.Length, ReadCallBack, myRequestState);</code>

<code>                </code><code>}</code>

<code>                </code><code>else</code>

<code>                    </code><code>Console.WriteLine(</code><code>"\nThe Length of the File is: {0}"</code><code>, myRequestState.filestream.Length);</code>

<code>                    </code><code>Console.WriteLine(</code><code>"DownLoad Completely, Download path is: {0}"</code><code>, myRequestState.savepath);</code>

<code>                    </code><code>myRequestState.response.Close();</code>

<code>                    </code><code>myRequestState.filestream.Close();</code>

<code>                </code><code>}    </code>

<code>                </code><code>Console.WriteLine(</code><code>"Error Message is:{0}"</code><code>, e.Message);</code>

<code>        </code><code>#endregion</code>

運作結果為(從運作結果也可以看出,在主線程中調用 DownloadFileAsync(downUrl)方法時,DownloadFileAsync(downUrl)方法中的myHttpWebRequest.BeginGetResponse調用被沒有阻塞調用線程(即主線程),而是立即傳回到主線程,是主線程後面的代碼可以立即執行)

[你必須知道的異步程式設計]——異步程式設計模型(APM)

如果我們調用的是同步方法時,此時會堵塞主線程,直到檔案的下載下傳操作被完成之後主線程才繼續執行後面的代碼,下面是下載下傳檔案的同步方法:

<code>#region Download File Synchrously</code>

<code>        </code><code>private</code> <code>static</code> <code>void</code> <code>DownLoadFileSync(</code><code>string</code> <code>url)</code>

<code>            </code><code>// Create an instance of the RequestState</code>

<code>            </code><code>RequestState requestState=</code><code>new</code> <code>RequestState();</code>

<code>                </code><code>// assign HttpWebRequest instance to its request field.</code>

<code>                </code><code>requestState.response = (HttpWebResponse)myHttpWebRequest.GetResponse();</code>

<code>                </code><code>requestState.streamResponse = requestState.response.GetResponseStream();</code>

<code>                </code><code>int</code> <code>readSize = requestState.streamResponse.Read(requestState.BufferRead, 0, requestState.BufferRead.Length);</code>

<code>                </code><code>while</code> <code>(readSize &gt; 0)</code>

<code>                    </code><code>requestState.filestream.Write(requestState.BufferRead, 0, readSize);</code>

<code>                    </code><code>readSize = requestState.streamResponse.Read(requestState.BufferRead, 0, requestState.BufferRead.Length);</code>

<code>                </code><code>Console.WriteLine(</code><code>"\nThe Length of the File is: {0}"</code><code>, requestState.filestream.Length);</code>

<code>                </code><code>Console.WriteLine(</code><code>"DownLoad Completely, Download path is: {0}"</code><code>, requestState.savepath);</code>

<code>            </code><code>finally</code>

<code>                </code><code>requestState.response.Close();</code>

<code>                </code><code>requestState.filestream.Close();</code>

使用同步方法下載下傳檔案的運作結果為(大家可以對照兩個方式的結果就可以明顯看出他們的差別了。):

[你必須知道的異步程式設計]——異步程式設計模型(APM)

四、使用委托也可以實作異步程式設計,你知道否?

4.1 使用委托實作更好的使用者體驗——不堵塞UI線程

雖然第一種方案是一種不推薦的方案,但是我覺得有些朋友還是不知道怎麼實作的,是以在這部分就用具體的代碼來實作下,并且該實作也可以與使用同步上下文對象的方式進行對比,這樣大家就可以更加了解如何使用委托來進行異步程式設計了。下面就具體看實作代碼吧:

62

63

64

65

66

67

68

69

<code>View Code</code>

<code> </code><code>// 定義用來實作異步程式設計的委托</code>

<code>        </code><code>private</code> <code>delegate</code> <code>string</code> <code>AsyncMethodCaller(</code><code>string</code> <code>fileurl);</code>

<code>        </code><code>public</code> <code>Mainform()</code>

<code>            </code><code>InitializeComponent();</code>

<code>            </code><code>txbUrl.Text = </code><code>"http://download.microsoft.com/download/7/0/3/703455ee-a747-4cc8-bd3e-98a615c3aedb/dotNetFx35setup.exe"</code><code>;</code>

<code>                                                                              </code> 

<code>            </code><code>// 允許跨線程調用</code>

<code>            </code><code>// 實際開發中不建議這樣做的,違背了.NET 安全規範</code>

<code>            </code><code>CheckForIllegalCrossThreadCalls = </code><code>false</code><code>;</code>

<code>        </code><code>private</code> <code>void</code> <code>btnDownLoad_Click(</code><code>object</code> <code>sender, EventArgs e)</code>

<code>            </code><code>rtbState.Text = </code><code>"Download............"</code><code>;</code>

<code>            </code><code>if</code> <code>(txbUrl.Text == </code><code>string</code><code>.Empty)</code>

<code>                </code><code>MessageBox.Show(</code><code>"Please input valid download file url"</code><code>);</code>

<code>                </code><code>return</code><code>;</code>

<code>            </code><code>AsyncMethodCaller methodCaller = </code><code>new</code> <code>AsyncMethodCaller(DownLoadFileSync);</code>

<code>            </code><code>methodCaller.BeginInvoke(txbUrl.Text.Trim(), GetResult, </code><code>null</code><code>);</code>

<code>        </code><code>// 同步下載下傳檔案的方法</code>

<code>        </code><code>// 該方法會阻塞主線程,使使用者無法對界面進行操作</code>

<code>        </code><code>// 在檔案下載下傳完成之前,使用者甚至都不能關閉運作的程式。</code>

<code>        </code><code>private</code> <code>string</code> <code>DownLoadFileSync(</code><code>string</code> <code>url)</code>

<code>            </code><code>RequestState requestState = </code><code>new</code> <code>RequestState();</code>

<code>                                                                                </code> 

<code>                </code><code>// 執行該方法的線程是線程池線程,該線程不是與建立richTextBox控件的線程不是一個線程</code>

<code>                </code><code>// 如果不把 CheckForIllegalCrossThreadCalls 設定為false,該程式會出現“不能跨線程通路控件”的異常</code>

<code>                </code><code>return</code> <code>string</code><code>.Format(</code><code>"The Length of the File is: {0}"</code><code>, requestState.filestream.Length) + </code><code>string</code><code>.Format(</code><code>"\nDownLoad Completely, Download path is: {0}"</code><code>, requestState.savepath);</code>

<code>                </code><code>return</code> <code>string</code><code>.Format(</code><code>"Exception occurs in DownLoadFileSync method, Error Message is:{0}"</code><code>, e.Message);</code>

<code>        </code><code>// 異步操作完成時執行的方法</code>

<code>        </code><code>private</code> <code>void</code> <code>GetResult(IAsyncResult result)</code>

<code>            </code><code>AsyncMethodCaller caller = (AsyncMethodCaller)((AsyncResult)result).AsyncDelegate;</code>

<code>            </code><code>// 調用EndInvoke去等待異步調用完成并且獲得傳回值</code>

<code>            </code><code>// 如果異步調用尚未完成,則 EndInvoke 會一直阻止調用線程,直到異步調用完成</code>

<code>            </code><code>string</code> <code>returnstring= caller.EndInvoke(result);</code>

<code>            </code><code>//sc.Post(ShowState,resultvalue);</code>

<code>            </code><code>rtbState.Text = returnstring;    </code>

運作的結果為:

[你必須知道的異步程式設計]——異步程式設計模型(APM)

4.2 線上程中通路另一個線程建立的控件

這部分将使用同步上下文的方式來實作線上程池線程中如何更新GUI線程中窗體,因為在程式代碼部分都有詳細的解釋,這裡就直接貼代碼了

70

71

72

73

74

75

76

77

78

79

80

81

82

<code>public</code> <code>partial</code> <code>class</code> <code>MainForm : Form</code>

<code>    </code><code>{</code>

<code>        </code><code>// 定義用來實作異步程式設計的委托</code>

<code>          </code><code>// 定義顯示狀态的委托</code>

<code>        </code><code>private</code> <code>delegate</code> <code>void</code> <code>ShowStateDelegate(</code><code>string</code> <code>value);</code>

<code>        </code><code>private</code> <code>ShowStateDelegate showStateCallback;</code>

<code>        </code><code>SynchronizationContext sc;</code>

<code>        </code><code>public</code> <code>MainForm()</code>

<code>            </code><code>showStateCallback = </code><code>new</code> <code>ShowStateDelegate(ShowState);</code>

<code>            </code><code>btnDownLoad.Enabled = </code><code>false</code><code>;</code>

<code>            </code><code>// 捕捉調用線程的同步上下文派生對象</code>

<code>            </code><code>sc = SynchronizationContext.Current;</code>

<code>            </code><code>string</code> <code>returnstring = caller.EndInvoke(result);</code>

<code>            </code><code>// 通過獲得GUI線程的同步上下文的派生對象,</code>

<code>            </code><code>// 然後調用Post方法來使更新GUI操作方法由GUI 線程去執行</code>

<code>            </code><code>sc.Post(ShowState,returnstring);  </code>

<code>        </code><code>// 顯示結果到richTextBox</code>

<code>        </code><code>// 因為該方法是由GUI線程執行的,是以當然就可以通路窗體控件了</code>

<code>        </code><code>private</code> <code>void</code> <code>ShowState(</code><code>object</code> <code>result)</code>

<code>            </code><code>rtbState.Text = result.ToString();</code>

<code>            </code><code>btnDownLoad.Enabled = </code><code>true</code><code>;</code>

<code>    </code><code>}</code>

程式的運作結果和前面使用第一方案的結果是一樣的,這裡就不重複貼圖了,上面所有的實作都是部分代碼,你可以在文章的最後下載下傳本專題的所有源碼。

五、小結

  到這裡本專題關于異步程式設計模型的介紹就結束了,異步程式設計模型(APM)雖然是.NET 1.0中提出來的一個模式,相對于現在來說是舊了點,并且微軟現在官方也表明在最新的代碼中不推薦使用該模型來實作異步的應用程式,而是推薦使用基于任務的異步程式設計模型來實作異步的應用程式,但是我個人認為,正是因為它是.NET 1.0中提出的來,并且現在來看确實有些舊了, 是以我們才更應該好好研究下它,因為後面提出的EAP和TAP微軟做了更多的封裝,是我們對異步程式設計的本質都不清楚的(其實它們的本質都是使用線程池和委托機制的,具體可以檢視前面的相關部分),并且系統學習下異步程式設計,也可以讓我們對新的異步程式設計模型的所帶來的好處有更可直覺的認識。在後面的一專題我将帶大家全面認識下基于事件的異步程式設計模型(EAP)。

<a href="http://down.51cto.com/data/2362807" target="_blank">附件:http://down.51cto.com/data/2362807</a>

     本文轉自LearningHard 51CTO部落格,原文連結:http://blog.51cto.com/learninghard/1197401,如需轉載請自行聯系原作者