免费高清特黄a大片,九一h片在线免费看,a免费国产一级特黄aa大,国产精品国产主播在线观看,成人精品一区久久久久,一级特黄aa大片,俄罗斯无遮挡一级毛片

分享

5天玩轉(zhuǎn)C#并行和多線程編程 —— 第一天 認識Parallel

 賈朋亮博客 2014-09-27
隨著多核時代的到來,并行開發(fā)越來越展示出它的強大威力!使用并行程序,充分的利用系統(tǒng)資源,提高程序的性能。在.net 4.0中,微軟給我們提供了一個新的命名空間:System.Threading.Tasks。這里面有很多關于并行開發(fā)的東西,今天第一篇就介紹下最基礎,最簡單的——認識和使用Parallel。

一、 Parallel的使用

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

1、 Parallel.Invoke

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

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

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

其使用方法如下:

var stopWatch = new StopWatch(); //創(chuàng)建一個Stopwatch實例

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

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

stopWatch.Reset(); //重置StopWatch

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

stopWatch.ElapsedMilliseconds //獲取stopWatch從開始到現(xiàn)在的時間差,單位是毫秒

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

下面進入整體,開始介紹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,分別用兩種方法調(diào)用Run1和Run2,然后在main方法中調(diào)用,下面來看一下運行時間如何:

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

2、Parallel.For

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

復制代碼
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.");
           
     }
復制代碼

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

可以看到,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跟之前的差不多。這主要是由于并行同時訪問全局變量,會出現(xiàn)資源爭奪,大多數(shù)時間消耗在了資源等待上面。

一直說并行,那么從哪里可以看出來Parallel.For是并行執(zhí)行的呢?下面來寫個測試代碼:

Parallel.For(0, 100, i =>
            {
               Console.Write(i + "\t");
            });

從0輸出到99,運行后會發(fā)現(xiàn)輸出的順序不對,用for順序肯定是對的,并行同時執(zhí)行,所以會出現(xiàn)輸出順序不同的情況。

2、Parallel.Foreach

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

List<int> list = new List<int>();
            list.Add(0);
            Parallel.ForEach(list, item =>
            {
               DoWork(item);
            });

二、 Parallel中途退出循環(huán)和異常處理

1、當我們使用到Parallel,必然是處理一些比較耗時的操作,當然也很耗CPU和內(nèi)存,如果我們中途向停止,怎么辦呢?

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

該實例提供了Break和Stop方法來幫我們實現(xiàn)。

Break: 當然這個是通知并行計算盡快的退出循環(huán),比如并行計算正在迭代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,當數(shù)量達到300個時,會立刻停止;可以看到結果"Bag count is 300",如果用break,可能結果是300多個或者300個,大家可以測試一下。

2、異常處理

  首先任務是并行計算的,處理過程中可能會產(chǎn)生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.");
         }
}
復制代碼

順序調(diào)用方法我把異常處理寫一起了,這樣只能捕獲Run1的異常信息,大家可以分開寫。捕獲AggregateException 異常后,用foreach循環(huán)遍歷輸出異常信息,可以看到兩個異常信息都顯示了。

點擊這里,下載源碼

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多