1. 程式人生 > >【C#】Parallel.For 和 For 誰的效率高呢?

【C#】Parallel.For 和 For 誰的效率高呢?

原標題:C# 多執行緒 Parallel.For 和 For 誰的效率高?那麼 Parallel.ForEach 和 ForEach 呢?

今天和大家探討一個問題:Parallel.For 和 For 誰的效率高呢?

從CPU使用方面而言,Parallel.For 屬於多執行緒範疇,可以開闢多個執行緒使用CPU核心,也就是說可以並行處理程式。For 迴圈是單執行緒的,一個執行緒執行完所有迴圈。

因此你會認為:多執行緒的效率肯定高於單執行緒。但這樣認為是錯誤的!

例如下面程式:

複製程式碼

static void Main(string[] args)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();

            ParallelLoopResult result =
            Parallel.For(0, 10000, i =>
            {
                Console.Write("");

            });
            sw.Stop();
            TimeSpan ts2 = sw.Elapsed;
            Console.WriteLine("Parallel.For總共花費{0}ms.", ts2.TotalMilliseconds);

            //
            Stopwatch sw_Eq = new Stopwatch();
            sw_Eq.Start();
            for (int i = 0; i < 10000; i++)
            {
                Console.Write(""); 
            }
            sw_Eq.Stop();
            TimeSpan tssw_Eq = sw_Eq.Elapsed;
            Console.WriteLine("for總共花費{0}ms.", tssw_Eq.TotalMilliseconds);
            Console.ReadKey();
        }

複製程式碼

額,為什麼For 迴圈要比Parallel.For 效率要高呢?

這是因為迴圈體內執行的任務開銷太小,僅僅是輸出一個空字串而已。微軟的文章已經指出任務的開銷大小對並行任務的影響。如果任務很小,那麼由於並行管理的附加開銷(任務分配,排程,同步等成本),可能並行執行並不是優化方案。這也是上述程式For效率高出的原因。

如果在迴圈體內執行向資料庫插入操作,那麼Parallel.For 效率就會高出,在此,我們認為每向資料庫插入一條記錄花費1毫秒時間,將程式修改如下:

複製程式碼

class Program
    {
        static void Main(string[] args)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();

            ParallelLoopResult result =
            Parallel.For(0, 10, i =>
            {
                Console.Write("");
                Thread.Sleep(1);

            });
            sw.Stop();
            TimeSpan ts2 = sw.Elapsed;
            Console.WriteLine("Parallel.For總共花費{0}ms.", ts2.TotalMilliseconds);

            //
            Stopwatch sw_Eq = new Stopwatch();
            sw_Eq.Start();
            for (int i = 0; i < 10; i++)
            {
                Console.Write("");
                Thread.Sleep(1);
            }
            sw_Eq.Stop();
            TimeSpan tssw_Eq = sw_Eq.Elapsed;
            Console.WriteLine("for總共花費{0}ms.", tssw_Eq.TotalMilliseconds);
            Console.ReadKey();
        }
    }
}

複製程式碼

執行結果大大改變:

相信到此,大家應該明白了吧!也就說For是同步,Parallel.For 是非同步執行。當然,我們也可以使用Thread實現非同步程式設計:

程式碼如下:

複製程式碼

  class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("主執行緒測試開始..");
            Thread th = new Thread(ThMethod);
            th.Start();
            Thread.Sleep(1000);
            Console.WriteLine("主執行緒測試結束..");
            Console.ReadLine();
        }


        static void ThMethod()
        {
            Console.WriteLine("非同步執行開始");
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine("非同步執行" + i.ToString() + "..");
                Thread.Sleep(1000);
            }
            Console.WriteLine("非同步執行完成");
        }
    }

複製程式碼

Parallel.ForEach 和 ForEach  與 Parallel.For 和 For 一樣,一個是非同步執行,開闢多個執行緒。一個是同步執行,開闢一個執行緒。因此,效率方面同上,主要看執行的什麼任務,在此不作具體說明。

下面寫了一些程式碼,從下面的程式碼中我們可以看出Parallel.ForEach具體開闢了幾個執行緒,如下:

複製程式碼

class Program
    {
        static void Main(string[] args)
        {
            int[] intList = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
            ParallelLoopResult result = Parallel.ForEach(intList, (s,pls,longs) =>
            {
                Console.WriteLine(longs + "  " + s);
                pls.Stop();
                if (pls.IsStopped)
                {
                    Parallel.Invoke(Gs,Ks);//非同步呼叫多個方法
                }
            });
            Console.ReadKey();
        }

        public static void Gs()
        {
            Console.WriteLine("非同步方法1");
        }

        public static void Ks()
        {
            Console.WriteLine("非同步方法2");
        }
    }

複製程式碼

上述程式碼中,呼叫了Stop()方法,我們都知道,如果是同步執行的,呼叫Stop()後,會立即停止執行,那麼程式只會輸出索引值為0的結果。而在非同步中不是這樣的,非同步迭代是多執行緒且沒有順序的。其執行結果如下:

多次執行的結果可能不同。

如上圖所示,第一個圖開闢了三個執行緒,執行順序為 0 2 1,第二個圖開闢了兩個執行緒,執行順序為:1 0 

下面的Invoke()方法是非同步呼叫其他的方法,在此不作解釋,可參考C# Invoke()

設定開啟的執行緒的個數:

  Parallel.ForEach(NameArray,new ParallelOptions{MaxDegreeOfParallelism=3},(item,pls,i)=>
            {
               
           });