C#多線程之旅(4)——APM初探

源碼地址:https://github.com/Jackson0714/Threadshtml

 

原文地址:C#多線程之旅(4)——APM初探git

C#多線程之旅目錄:github

C#多線程之旅(1)——介紹和基本概念面試

C#多線程之旅(2)——建立和開始線程編程

C#多線程之旅(3)——線程池多線程

C#多線程之旅(4)——APM初探異步

C#多線程之旅(5)——同步機制介紹異步編程

C#多線程之旅(6)——詳解多線程中的鎖工具

更多文章正在更新中,敬請期待......post

 

C#多線程之旅(4)——APM初探

v博客前言

先交代下背景,前面幾張內容主要是介紹多線程的基本知識,這一章是由於正好接觸到了APM(異步編程模型),發現APM真的很強大,其中有部分知識點涉及到了委託的BeginInvoke/EndInvoke,就由衷地想寫下APM相關的知識。

v寫在前面

強大的異步處理模型,不得不被它折服!

v正文開始

1、簡單的串行執行程序

 咱們先來看一個簡單的程序:
定義了一個 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的時間。

 2、使用委託來實現APM

2.1 預備知識

咱們使用泛型委託來實現APM,那麼咱們須要點預備知識(對委託很熟練的同窗們能夠跳過預備知識):
  1.什麼是委託?
  2.什麼是泛型委託?
  3.爲何使用委託來實現APM?
對於這知識點一、2,能夠參考我以前寫的博客,在這裏就再也不說明了, 不懼面試:委託
對於第三個知識點,是由於委託定義了兩個異步方法 BeginInvokeEndInvoke
咱們能夠先看看泛型委託的定義:
/// <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#編譯器會將這行代碼編譯成一個類定義,它的邏輯定義以下:

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方法的類。

當定義下面的委託時

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/
關於做者:專一於微軟平臺的項目開發。若有問題或建議,請多多賜教!
版權聲明:本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文連接。
特此聲明:全部評論和私信都會在第一時間回覆。也歡迎園子的大大們指正錯誤,共同進步。或者直接私信
聲援博主:若是您以爲文章對您有幫助,能夠點擊文章右下角推薦一下。您的鼓勵是做者堅持原創和持續寫做的最大動力!

相關文章
相關標籤/搜索