天天看點

5天玩轉C#并行和多線程程式設計 —— 第一天 認識Parallel

5天玩轉C#并行和多線程程式設計系列文章目錄

<a href="http://www.cnblogs.com/yunfeifei/p/3993401.html">5天玩轉C#并行和多線程程式設計 —— 第一天 認識Parallel</a>

<a href="http://www.cnblogs.com/yunfeifei/p/3998783.html">5天玩轉C#并行和多線程程式設計 —— 第二天 并行集合和PLinq</a>

<a href="http://www.cnblogs.com/yunfeifei/p/4106318.html">5天玩轉C#并行和多線程程式設計 —— 第三天 認識和使用Task</a>

<a href="http://www.cnblogs.com/yunfeifei/p/4111112.html">5天玩轉C#并行和多線程程式設計 —— 第四天 Task進階</a>

<a href="http://www.cnblogs.com/yunfeifei/p/4122084.html">5天玩轉C#并行和多線程程式設計 —— 第五天 多線程程式設計大總結</a>

  随着多核時代的到來,并行開發越來越展示出它的強大威力!使用并行程式,充分的利用系統資源,提高程式的性能。在.net 4.0中,微軟給我們提供了一個新的命名空間:System.Threading.Tasks。這裡面有很多關于并行開發的東西,今天第一篇就介紹下最基礎,最簡單的——認識和使用Parallel。

  一、 Parallel的使用

在Parallel下面有三個常用的方法invoke,For和ForEach。

1、  Parallel.Invoke

這是最簡單,最簡潔的将串行的代碼并行化。

在這裡先講一個知識點,就是StopWatch的使用,最近有一些人說找不到StopWatch,StopWatch到底是什麼東西,今天就來說明一下。

StopWatch在System.Diagnostics命名控件,要使用它就要先引用這個命名空間。

其使用方法如下:

var stopWatch = new StopWatch();   //建立一個Stopwatch執行個體

stopWatch.Start();   //開始計時

stopWatch.Stop();   //停止計時

stopWatch.Reset();  //重置StopWatch

stopWatch.Restart(); //重新啟動被停止的StopWatch

stopWatch.ElapsedMilliseconds //擷取stopWatch從開始到現在的時間差,機關是毫秒

本次用到的就這麼多知識點,想了解更多關于StopWatch的,去百度一下吧,網上有很多資料。

下面進入整體,開始介紹Parallel.Invoke方法,廢話不多說了,首先建立一個控制台程式,添加一個類,代碼如下:

代碼很簡單,首先新加一個類,在類中寫了兩個方法,Run1和Run2,分别等待一定時間,輸出一條資訊,然後寫了一個測試方法ParallelInvokeMethod,分别用兩種方法調用Run1和Run2,然後在main方法中調用,下面來看一下運作時間如何:

5天玩轉C#并行和多線程程式設計 —— 第一天 認識Parallel

  大家應該能夠猜到,正常調用的話應該是5秒多,而Parallel.Invoke方法調用用了隻有3秒,也就是耗時最長的那個方法,可以看出方法是并行執行的,執行效率提高了很多。

2、Parallel.For

這個方法和For循環的功能相似,下面就在類中添加一個方法來測試一下吧。代碼如下:

寫了兩個循環,做了一些沒有意義的事情,目的主要是為了消耗CPU時間,同理在main方法中調用,運作結果如下圖:

5天玩轉C#并行和多線程程式設計 —— 第一天 認識Parallel

可以看到,Parallel.For所用的時間比單純的for快了1秒多,可見提升的性能是非常可觀的。那麼,是不是Parallel.For在任何時候都比for要快呢?答案當然是“不是”,要不然微軟還留着for幹嘛?

下面修改一下代碼,添加一個全局變量num,代碼如下:

Parallel.For由于是并行運作的,是以會同時通路全局變量num,為了得到正确的結果,要使用lock,此時來看看運作結果:

5天玩轉C#并行和多線程程式設計 —— 第一天 認識Parallel

  是不是大吃一驚啊?Parallel.For竟然用了15秒多,而for跟之前的差不多。這主要是由于并行同時通路全局變量,會出現資源争奪,大多數時間消耗在了資源等待上面。

一直說并行,那麼從哪裡可以看出來Parallel.For是并行執行的呢?下面來寫個測試代碼:

從0輸出到99,運作後會發現輸出的順序不對,用for順序肯定是對的,并行同時執行,是以會出現輸出順序不同的情況。

2、Parallel.Foreach

這個方法跟Foreach方法很相似,想具體了解的,可以百度些資料看看,這裡就不多說了,下面給出其使用方法:

 二、 Parallel中途退出循環和異常處理

1、當我們使用到Parallel,必然是處理一些比較耗時的操作,當然也很耗CPU和記憶體,如果我們中途向停止,怎麼辦呢?

在串行代碼中我們break一下就搞定了,但是并行就不是這麼簡單了,不過沒關系,在并行循環的委托參數中提供了一個ParallelLoopState,

該執行個體提供了Break和Stop方法來幫我們實作。

Break: 當然這個是通知并行計算盡快的退出循環,比如并行計算正在疊代100,那麼break後程式還會疊代所有小于100的。

Stop:這個就不一樣了,比如正在疊代100突然遇到stop,那它啥也不管了,直接退出。

下面來寫一段代碼測試一下:

這裡使用的是Stop,當數量達到300個時,會立刻停止;可以看到結果"Bag count is 300",如果用break,可能結果是300多個或者300個,大家可以測試一下。

2、異常處理

  首先任務是并行計算的,處理過程中可能會産生n多的異常,那麼如何來擷取到這些異常呢?普通的Exception并不能擷取到異常,然而為并行誕生的AggregateExcepation就可以擷取到一組異常。

這裡我們修改Parallel.Invoke的代碼,修改後代碼如下:

順序調用方法我把異常處理寫一起了,這樣隻能捕獲Run1的異常資訊,大家可以分開寫。捕獲AggregateException 異常後,用foreach循環周遊輸出異常資訊,可以看到兩個異常資訊都顯示了。

<a href="http://files.cnblogs.com/yunfeifei/5%E5%A4%A9%E7%8E%A9%E8%BD%AC%E5%B9%B6%E8%A1%8C%E7%BC%96%E7%A8%8B-%E7%AC%AC%E4%B8%80%E5%A4%A9%E4%BB%A3%E7%A0%81.rar">點選這裡,下載下傳源碼</a>

繼續閱讀