微軟的並行運算平台(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占用。