C#多线程之旅(4)——APM初探
閱讀目錄
- 一、簡單的串行執行程序
- ?二、使用委托來實現APM
源碼地址:https://github.com/Jackson0714/Threads
C#多線程之旅(4)——APM初探
v博客前言
先交代下背景,前面幾張內容主要是介紹多線程的基本知識,這一章是因為正好接觸到了APM(異步編程模型),發現APM真的很強大,其中有部分知識點涉及到了委托的BeginInvoke/EndInvoke,就由衷地想寫下APM相關的知識。
v寫在前面
強大的異步處理模型,不得不被它折服!
v正文開始
回到頂部
一、簡單的串行執行程序
?我們先來看一個簡單的程序:
定義了一個int Add(int num),傳入循環的次數num,返回循環相加的結果sum。
Step 1.Main方法調用Add方法,循環執行了2次,所以延時了2s,返回結果sum=1,打印?Result:1;
Step 2.Main方法循環執行了3次,延時了3s。
友情提醒:如果覺得不想閱讀多彩的Console打印代碼,可以選擇查看下面折疊的code區域。查看簡潔版
?去掉顏色打印的code簡潔版
?讓我們看看這個程序的運行結果:
?我們可以從結果中看到:
1.執行Add方法,是主線程執行Add方法;
2.執行Main方法,是主線程執行Main方法;
3.這中限時操作可以稱為“計算限制的異步操作”;
4.Add方法中模擬耗時操作(2s)和Main方法中模擬耗時操作(3s)是串行執行的,那么我們有沒有一種方法使這兩種操作并行執行了?(3s中之內搞定這兩個耗時操作)。答案是可以用APM。
?
?下面我們用APM方式來節省2s的時間。
回到頂部
?二、使用委托來實現APM
2.1 預備知識
我們使用泛型委托來實現APM,那么我們需要點預備知識(對委托很熟練的同學們可以跳過預備知識):
1.什么是委托?
2.什么是泛型委托?
3.為什么使用委托來實現APM?
對于這知識點1、2,可以參考我之前寫的博客,在這里就不再說明了,不懼面試:委托
對于第三個知識點,是因為委托定義了兩個異步方法BeginInvoke和EndInvoke。
我們可以先看看泛型委托的定義:
| 1 2 3 4 5 6 7 8 | /// <summary> /// 定義一個泛型委托 /// </summary> /// <typeparam name="T">輸入參數</typeparam> /// <typeparam name="TResult">返回值</typeparam> /// <param name="arg">輸入參數</param> /// <returns name="TResult">返回值</returns> private?delegate?TResult Func<T, TResult>(T arg); |
對于這個定義,C#編譯器會將這行代碼編譯成一個類定義,它的邏輯定義如下:
| 1 2 3 4 5 6 7 | public?sealed?class?Func<T, TResult> : MulticastDelegate { ????public?Func(Object obj, IntPtr method); ????public?TResult Invoke(T arg); ????public?IAsyncResult BeginInvoke(T arg, AsyncCallback callback, Object obj); ????public?TResult EndInvoke(IAsyncResult result); } |
定義一個委托時,會生成一個BeginInvoke和EndInvoke方法的類。
當定義下面的委托時
| 1 | public?delegate?void?myDelegate(int?value); |
通過反編譯工具ILSpy查看結果:
BeginInvoke:
1.第一個參數arg為委托定義相同的參數(可以為兩個參數arg,和委托的簽名相同),可以傳入到委托引用的方法;
2.倒數第二個參數callback為回調方法,當BeginInvoke方法執行完后,會立即調用回調方法,如果callback=null,則不調用回調方法;
3.倒數第一個參數object給EndInvoke用的。
4.返回值為IAsyncResult類型的接口對象(實際上是AsynResult的類型實例)。該接口對象用途
a.傳遞參數,它包含了對調用了BeginInvoke的委托的引用,這里是Add方法的int類型的輸入參數;
b.包含了BeginInvoke()的最后一個Object類型的參數
c.它可以鑒別是哪個方法的哪一次調用,因為通過同一個委托變量可以對同一個方法調用多次。
EndInvoke:
1.第一個參數接收BeginInvoke返回的IAnsyResult;
2.返回的TResult為委托引用的方法的返回值,這里是Add方法的int類型返回值
2.2 用委托來實現APM的原理
2.3 動手寫個實現了APM的Code
通過上面的流程圖,相信我們對委托來實現APM有了一定的理解,再來讀讀code,相信能更快地理解。注釋僅作參考,有問題可以回復我哦!
讓我們看看結果:
?注意:
1.必須先將IAsyncResult轉換為AsyncResult,才能獲取到引用的委托,因為它沒有包含在IAsyncResult接口的定義中;
2.Add方法的調用,AddCallback方法都是線程池線程調用的;
3.BeginInvoke的object參數可以為任何類型,例子中傳遞的是string類型的參數"I'm here!";
4.主線程執行的for循環和Add方法中線程是同時進行的,交替打印結果;
5.當異步的Add方法沒有執行完畢,調用EndInvoke,則會阻塞當前線程池線程,只有異步方法執行完畢后,才會繼續執行的代碼;
6.Add方法執行完后,會自動調用回調方法AddCallback;
7.在調用EndInvoke可能拋出異常,所以需要加try/catch/finally,捕獲EndInvoke的可能拋出的異常。
?
v寫在最后
因為只是剛開始接觸APM相關的知識,所以本篇只是寫初探的內容,后面的章節會更多地介紹這方面的內容。希望得到園友們的支持!
作 者:?Jackson0714?
出 處:http://www.cnblogs.com/jackson0714/?
關于作者:專注于微軟平臺的項目開發。如有問題或建議,請多多賜教!?
版權聲明:本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接。?
特此聲明:所有評論和私信都會在第一時間回復。也歡迎園子的大大們指正錯誤,共同進步。或者直接私信我?
聲援博主:如果您覺得文章對您有幫助,可以點擊文章右下角【推薦】一下。您的鼓勵是作者堅持原創和持續寫作的最大動力!?
總結
以上是生活随笔為你收集整理的C#多线程之旅(4)——APM初探的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 产油国的大举减产开始出效果,美原油大涨1
- 下一篇: NuGet的使用、部署、搭建私有服务