Parallel.Foreach的基礎知識


 

微軟的並行運算平台(Microsoft’s Parallel Computing Platform (PCP))提供了這樣一個工具,讓軟件開發人員可以有效的使用多核提供的性能.

Visual Studio 2010 和 .NET Framework 4 提供了新的運行時、新的類庫類型以及新的診斷工具,從而增強了對並行編程的支持。 這些功能簡化了並行開發,使您能夠通過固有方法編寫高效、細化且可伸縮的並行代碼,而不必直接處理線程或線程池.

 

實驗1:測試一般Foreach,Parallel.For,Parallel.Foreach三種情況的效率問題,執行方法:Tostring()

測試結果:

源碼:

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 測試ParallelFor
{
    class Program
    {
        /*
        * 測試分析結果
        * Parallel.For、Parallel.Foreach發揮出了平行運算的優勢,將效率提高了接近一半左右。
        * 
        * 測試總結
        * 對於Parallel.For、Parallel.Foreach的使用應該要特別小心,
        * 它們的優勢是處理列表很長,且對列表內的元素進行很復雜的業務邏輯,且不會使用共享資源,
        * 只針對自身的業務邏輯處理,方才能提升效率。
        * 因為如果邏輯過於簡單的話,創建線程的花費將大於業務執行的花費,得不償失。         
        */
        static void Main(string[] args)
        {
            //產生測試資料
            List<int> testData = new List<int>();
            Random Rand = new Random();
            //產生亂數列表
            for (int i = 0; i < 1000000; i++)
            {
                testData.Add(Rand.Next(1000));
            }
            //打印正確結果
            Console.WriteLine(testData.Sum());

            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine();
                TestFor(testData);
                TestParallelFor(testData);
                TestParallelForeach(testData);
            }
            Console.ReadKey();
        }

        static void TestFor(List<int> testData)
        {
            DateTime time1 = DateTime.Now;
            foreach (var item in testData)
            {
                item.ToString();
            }
            Console.WriteLine(string.Format("ForEach:     t{0} in {1}", testData.Sum(), (DateTime.Now - time1).TotalMilliseconds));
        }

        static void TestParallelFor(List<int> testData)
        {
            DateTime time1 = DateTime.Now;
            Parallel.For(0, testData.Count, (i, loopState) =>
            {
                testData[i].ToString();
            });
            Console.WriteLine(string.Format("Parallel.For:   t{0} in {1}", testData.Sum(), (DateTime.Now - time1).TotalMilliseconds));
        }

        static void TestParallelForeach(List<int> testData)
        {
            //記錄結果用
            DateTime time1 = DateTime.Now;
            Parallel.ForEach(testData, (item, loopState) =>
            {
                item.ToString();
            });
            Console.WriteLine(string.Format("Parallel.ForEach:t{0} in {1}", testData.Sum(), (DateTime.Now - time1).TotalMilliseconds));
        }
    }
}

 

實驗2:Parallel的線程管理情況

測試結果:

Parallel會再最近的一個thread結束后,把該完成的ThreadId作為新的開辟的線程的Id,

源碼:

實驗3:最大線程數。線程是CPU進行調度的單位,進程是系統進程調度的單位。線程組成進程。設置平行運行最大最大線程數:2個;這樣系統運行可控,不會造成高CPU的情況

結果及源碼:

 

實驗4:Parallel的跳出循環以及終止循環。

      Parallel.ForEach(list,new ParallelOptions(){ MaxDegreeOfParallelism=2}, (p, state1) =>
            { 
                Invoke(p);
                state1.Break();//Break用於根據條件過濾循環,Break不是Continue,不要搞混了!Break是執行完現有的迭代后跳出!
                state1.Stop();//Stop方法用於退出Paraller循環,表示立刻退循環,cease=終止
                return; //注意:不論是Break還是Stop方法,后面的return語句是必須的,否則當前循環體第13行的語句還是會被執行。
            });

 

ParallelLoopState.Stop() 提供了退出循環的方法,這種方式要比其他兩種方法更快。這個方法通知循環不要再啟動執行新的迭代,並盡可能快的推出循環。

ParallelLoopState.IsStopped 屬性可用來判定其他迭代是否調用了 Stop 方法。

Break不是Continue,不要搞混了!Break是執行完現有的迭代后跳出!

ParallelLoopState.Break() 通知循環繼續執行本元素前的迭代,但不執行本元素之后的迭代。最前調用 Break 的起作用,並被記錄到 ParallelLoopState.LowestBreakIteration 屬性中

 

其他知識點:

未設置最大線程數的情況下:

1.為設置最大線程的情況下,TPL默認線程數為任務數(系統允許的情況下,設置ThreadPool.SetMaxThreads沒有效果)。

2.TPL默認啟動5個線程,任務數小於5的話,啟動任務數個線程。

3.如果任務較多,TPL在初始化5個線程后,每隔100毫秒左右新增線程,直到達到最大線程數。如果新增線程的過程中有任務完成,那么就不會新增線程。

缺點:線程數無法控制,容易造成高CPU,系統失去響應。

4.容易帶來CPU占用。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM