您好,登錄后才能下訂單哦!
本篇文章給大家分享的是有關怎么在c#中使用Parallelx實現并行和多線程編程,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
一、 Parallel的使用
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方法,廢話不多說了,首先新建一個控制臺程序,添加一個類,代碼如下:
public class ParallelDemo { private Stopwatch stopWatch = new Stopwatch(); public void Run1() { Thread.Sleep(2000); Console.WriteLine("Task 1 is cost 2 sec"); } public void Run2() { Thread.Sleep(3000); Console.WriteLine("Task 2 is cost 3 sec"); } public void ParallelInvokeMethod() { stopWatch.Start(); Parallel.Invoke(Run1, Run2); stopWatch.Stop(); Console.WriteLine("Parallel run " + stopWatch.ElapsedMilliseconds + " ms."); stopWatch.Restart(); Run1(); Run2(); stopWatch.Stop(); Console.WriteLine("Normal run " + stopWatch.ElapsedMilliseconds + " ms."); } }
代碼很簡單,首先新加一個類,在類中寫了兩個方法,Run1和Run2,分別等待一定時間,輸出一條信息,然后寫了一個測試方法ParallelInvokeMethod,分別用兩種方法調用Run1和Run2,然后在main方法中調用,下面來看一下運行時間如何:
大家應該能夠猜到,正常調用的話應該是5秒多,而Parallel.Invoke方法調用用了只有3秒,也就是耗時最長的那個方法,可以看出方法是并行執行的,執行效率提高了很多。
這個方法和For循環的功能相似,下面就在類中添加一個方法來測試一下吧。代碼如下:
public void ParallelForMethod() { stopWatch.Start(); for (int i = 0; i < 10000; i++) { for (int j = 0; j < 60000; j++) { int sum = 0; sum += i; } } stopWatch.Stop(); Console.WriteLine("NormalFor run " + stopWatch.ElapsedMilliseconds + " ms."); stopWatch.Reset(); stopWatch.Start(); Parallel.For(0, 10000, item => { for (int j = 0; j < 60000; j++) { int sum = 0; sum += item; } }); stopWatch.Stop(); Console.WriteLine("ParallelFor run " + stopWatch.ElapsedMilliseconds + " ms."); }
寫了兩個循環,做了一些沒有意義的事情,目的主要是為了消耗CPU時間,同理在main方法中調用,運行結果如下圖:
可以看到,Parallel.For所用的時間比單純的for快了1秒多,可見提升的性能是非常可觀的。那么,是不是Parallel.For在任何時候都比for要快呢?答案當然是“不是”,要不然微軟還留著for干嘛?
下面修改一下代碼,添加一個全局變量num,代碼如下:
public void ParallelForMethod() { var obj = new Object(); long num = 0; ConcurrentBag<long> bag = new ConcurrentBag<long>(); stopWatch.Start(); for (int i = 0; i < 10000; i++) { for (int j = 0; j < 60000; j++) { //int sum = 0; //sum += item; num++; } } stopWatch.Stop(); Console.WriteLine("NormalFor run " + stopWatch.ElapsedMilliseconds + " ms."); stopWatch.Reset(); stopWatch.Start(); Parallel.For(0, 10000, item => { for (int j = 0; j < 60000; j++) { //int sum = 0; //sum += item; lock (obj) { num++; } } }); stopWatch.Stop(); Console.WriteLine("ParallelFor run " + stopWatch.ElapsedMilliseconds + " ms."); }
Parallel.For由于是并行運行的,所以會同時訪問全局變量num,為了得到正確的結果,要使用lock,此時來看看運行結果:
是不是大吃一驚啊?Parallel.For竟然用了15秒多,而for跟之前的差不多。這主要是由于并行同時訪問全局變量,會出現資源爭奪,大多數時間消耗在了資源等待上面。
一直說并行,那么從哪里可以看出來Parallel.For是并行執行的呢?下面來寫個測試代碼:
Parallel.For(0, 100, i => { Console.Write(i + "\t"); });
從0輸出到99,運行后會發現輸出的順序不對,用for順序肯定是對的,并行同時執行,所以會出現輸出順序不同的情況。
這個方法跟Foreach方法很相似,想具體了解的,可以百度些資料看看,這里就不多說了,下面給出其使用方法:
List<int> list = new List<int>(); list.Add(0); Parallel.ForEach(list, item => { DoWork(item); });
在串行代碼中我們break一下就搞定了,但是并行就不是這么簡單了,不過沒關系,在并行循環的委托參數中提供了一個ParallelLoopState,
該實例提供了Break和Stop方法來幫我們實現。
Break: 當然這個是通知并行計算盡快的退出循環,比如并行計算正在迭代100,那么break后程序還會迭代所有小于100的。
Stop:這個就不一樣了,比如正在迭代100突然遇到stop,那它啥也不管了,直接退出。
下面來寫一段代碼測試一下:
public void ParallelBreak() { ConcurrentBag<int> bag = new ConcurrentBag<int>(); stopWatch.Start(); Parallel.For(0, 1000, (i, state) => { if (bag.Count == 300) { state.Stop(); return; } bag.Add(i); }); stopWatch.Stop(); Console.WriteLine("Bag count is " + bag.Count + ", " + stopWatch.ElapsedMilliseconds); }
這里使用的是Stop,當數量達到300個時,會立刻停止;可以看到結果"Bag count is 300",如果用break,可能結果是300多個或者300個,大家可以測試一下。
首先任務是并行計算的,處理過程中可能會產生n多的異常,那么如何來獲取到這些異常呢?普通的Exception并不能獲取到異常,然而為并行誕生的AggregateExcepation就可以獲取到一組異常。
這里我們修改Parallel.Invoke的代碼,修改后代碼如下:
public class ParallelDemo { private Stopwatch stopWatch = new Stopwatch(); public void Run1() { Thread.Sleep(2000); Console.WriteLine("Task 1 is cost 2 sec"); throw new Exception("Exception in task 1"); } public void Run2() { Thread.Sleep(3000); Console.WriteLine("Task 2 is cost 3 sec"); throw new Exception("Exception in task 2"); } public void ParallelInvokeMethod() { stopWatch.Start(); try { Parallel.Invoke(Run1, Run2); } catch (AggregateException aex) { foreach (var ex in aex.InnerExceptions) { Console.WriteLine(ex.Message); } } stopWatch.Stop(); Console.WriteLine("Parallel run " + stopWatch.ElapsedMilliseconds + " ms."); stopWatch.Reset(); stopWatch.Start(); try { Run1(); Run2(); } catch(Exception ex) { Console.WriteLine(ex.Message); } stopWatch.Stop(); Console.WriteLine("Normal run " + stopWatch.ElapsedMilliseconds + " ms."); } }
以上就是怎么在c#中使用Parallelx實現并行和多線程編程,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。