.Net中的非同步編程模式 (APM) (一)

來源:互聯網
上載者:User
文章目錄
  • APM簡介
  • Threadpool與Computing-Bound, I/O-Bound操作

前段時間看奧運,一下子懶了下來,就停止更新了。本來上一篇,就準備寫XAML和Extension的東西,不過最近回顧了前面寫的東西,覺得有必要總結一下.Net中的非同步編程模式 (APM) 。計劃分四個部分:
  • 如何?支援APM的類
  • 如果實現支援APM的硬體裝置類
  • Event-based的APM
  • Continuation-passing Style(CPS)的APM
有些內容相關的文章已經很多了,我寫的內容也主要來源於MSDN CONCURRENT AFFAIRS系列。我主要想結合這些內容,看如果使用PowerThreading類庫來簡化我們的開發
在開始之前,讓我們看看非同步編程模式APM:APM簡介

APM的概念簡單來說就是,主線程建立一個線程執行比較費時的任務,而自己繼續執行其他任務。通過使用ThreadPool或者Thread,我們可以很容易的建立線程並讓其執行任務,問題的痛點在於主線程如何知道該任務是否結束,及如果取消,控制該任務的執行等。

.Net 1.x中定義了IAsyncResult介面,並且類庫中會執行費時任務的類都同時提供了同步和非同步API,如FileStream同步讀檔案的Read方法,對應的非同步版本BeginRead和EndRead。主線程調用BeginRead方法時,該方法立即返回一個IAsyncResult對象,而同時FileStream開始執行硬碟讀操作。IAsyncResult可以看作的這個讀操作的一個"Handler",定義如下:

1 public interface IAsyncResult {
2    WaitHandle AsyncWaitHandle { get; } // 用於等待直到完成方式
3    Boolean    IsCompleted     { get; } // 由於輪詢查看方式
4    Object     AsyncState      { get; } // 用於回調方式
5    Boolean    CompletedSynchronously { get; } // 幾乎重來不用
6 }

通過這個"Handler"我們可以採用3種方式來等待任務的結束。從這個介面定義,我們可以看出,IAsyncResult方法的局限性。當主線程發出非同步任務後,無法取消該任務,也無法知道該任務的執行進度等。我們將後面的內容中,在看如果改善這些問題。

另外,BeginXxx和EndXxx必須成對調用,BeginXxx用於觸發任務的執行,EndXxx則用於獲得任務執行的返回。儘管有的任務不需要知道結果,但EndXxx還是得調用,否則會造成記憶體流失。如果可以採用回調方式,比較常見的方法就是在回呼函數中調用EndXxx。實現回呼函數,是比較討厭的事情,必需通過一定方法,類成員變數,AsyncState等,將FileStream對象傳遞進去。通過C# 2.0中Anonymous Method及 Limbda,我們可以簡化代碼,如下面的例子,通過Anonymous Method局部變數的捕獲功能,request局部變數漂亮的傳遞到回呼函數中。

 1 // C#2 匿名函數
 2 var request = HttpWebRequest.Create("http://www.google.com");
 3 var result = request.BeginGetResponse(
 4       delegate(IAsyncResult ar_)
 5       {
 6          var response = request.EndGetResponse(ar_);
 7          ProcessData(response);
 8       },
 9       null
10    );
11 
12 // C#3 Limbda
13 result = request.BeginGetResponse( 
14       ar_ => {
15          var response = request.EndGetResponse(ar_);
16          ProcessData(response);
17       },
18       null
19    );Threadpool與Computing-Bound, I/O-Bound操作剛開始看CLR via C#中,開始對Computing-Bound operation和IO-Bound operation的區別不是很理解。後來,結合.Net ThreadPool及Window中IO API及thread pool,才弄明白。

首先,我們知道.Net ThreadPool類中的線程分為Worker Thread和I/O Thread。預設情況下,Worker Thread是CPU*25個,而I/O Thread是1000個。.Net的ThreadPool是基於Windows OS本身提供的Thread Pool的。所以我們先看看Windows本身提供的Thread Pool。

Windows 的Thread Pool (Vista以前)中的線程也分為兩類I/O Worker Thread和non-I/O Worker Thread。當我們調用Windows API對I/O如檔案進行同步讀寫時,該線程建立一個IRP的裝置請求,並將IRP發送給device stack,然後在核心態等待其完成。而當我們用非同步方式時,該線程發送完IRP後,則返回,繼續後續的操作。Windows有很多種方式可以通知該I/O操作的完成,與Thread Pool相關的有兩種。一種是將完成notification放在該線程的APC隊列中,該隊列只有當線程進入等待狀態是,才會被讀取;而另一種方式則是I/O Completion Port,我們可以把這樣也認為是個隊列,而讀取這個隊列可以通過GetQueuedCompletionStatus API函數。Windows的Thread Pool的分類就是根據讀取不同的隊列。I/O Worker Thread讀取的是APC隊列,也就是當線程完成一個任務後,會進入等待狀態;而non-I/O Worker Thread則對應的讀取I/O Completion Port隊列。APC相比於I/O Completion Port存在很多問題,且效能較差,但是為了向後相容還是不得不支援。因而在.Net中,只封裝了I/O Completion Port,也就是.Net中的I/O Thread對於Windows中的non-I/O Worker Thread。呵呵,希望我還清醒。而APC對於的I/O Worker Thread則沒有.Net Thread Pool對應的。

所以在.Net線程池中,I/O Thread實際就是I/O完成連接埠,而Worker Thread可以看成.Net通過Thread類預先建立的一組線程。.Net及ThreadPool類中提供的方法,如QueueUserWorkItem, Timer, delegate回調等使用的都是Worker Thread。而.Net中對I/O操作的封裝,如FileStream, NetworkStream等則是使用的IO Thread。

讓我們在回頭看CLR via C#中提到的計算約束Computing-Bound和I/O約束I/O-Bound的操作。當我們調用FileStream.BeginRead讀檔案時,BeginRead並沒有建立新的線程去執行讀操作,讀操作(IRP)被裝置執行,同時該線程繼續執行其他任務。而當裝置完成讀操作後,線程池(IO Thread)中的一個線程開始執行回呼函數。

而當我們執行的是Computing-Bound的操作時,開始我們就新建立一個線程或通過ThreadPool.QueueUserWorkItem使用線程池中的線程來執行操作,任務完成後,這個線程會執行回呼函數。

通過上面的分析,我們可以看到真的不同操作類型,Computing-Bound vs I/O-Bound,類庫實現的方式是不同。當然,我們也可以非同步Computing-Bound的方式來同步調用FileStream.Read,但是這樣我們就沒有利用I/O完成連接埠這個高效能的特性。

本來想這篇就想寫如果使用PowerThreading來實現APM的,限於篇幅,就該在下篇吧。希望上面的內容對大家有協助

參考:

《CLR via C#》第23章 by Jeffery RichardImplementing the CLR Asynchronous Programming ModelSimplified APM with C#Windows I/O threads vs. managed I/O threads

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.