菜鳥學習並行編程,參考《C#並行編程高級教程.PDF》,若有錯誤,歡迎指正。html
C#並行編程-併發集合ide
TPL中引入了一個新命名空間System.Threading.Tasks,在該命名空間下Task是主類,表示一個類的異步的併發的操做,建立並行代碼的時候不必定要直接使用Task類,在某些狀況下能夠直接使用Parallel靜態類(System.Threading.Tasks.Parallel)下所提供的方法,而不用底層的Task實例。學習
Parallel.Invoke spa
試圖將不少方法並行運行,若是傳入的是4個方法,則至少須要4個邏輯內核才能足以讓這4個方法併發運行,邏輯內核也稱爲硬件線程。pwa
須要注意的是:1.即便擁有4個邏輯內核,也不必定可以保證所須要運行的4個方法可以同時啓動運行,若是其中的一個內核處於繁忙狀態,那麼底層的調度邏輯可能會延遲某些方法的初始化執行。
2.經過Parallel.Invoke編寫的併發執行代碼必定不能依賴與特定的執行順序,由於它的併發執行順序也是不定的。
3.使用Parallel.Invoke方法必定要測量運行結果、實現加速比以及邏輯內核的使用率,這點很重要。
4.使用Parallel.Invoke,在運行並行方法前都會產生一些額外的開銷,如分配硬件線程等。
好處:這是一種並行運行不少方法的簡單方式,使用Parallel.Invoke,不須要考慮任務和線程的問題。
下面貼代碼:
class Program { private static List<Product> ProductList = null; /* coder:釋迦苦僧 * 沒有特定的執行順序 * 示例中 基於電腦配置 採用了4個方法的並行編程 * Parallel.Invoke 首先會嘗試並行啓動4個方法,充分利用一個或多個物理處理器所提供的多個邏輯內核 * 可是在實際的並行執行中,至少要有4個邏輯內核才能知足4個方法的並行運行 * 若是有個或者多個邏輯內核處於繁忙狀態,那麼底層的調度邏輯可能會延遲某些方法的初始化執行 * 經過Parallel.Invoke編寫的併發執行代碼必定不能依賴與特定的執行順序,由於它的併發執行順序也是不定的。 */ static void Main(string[] args) { ProductList = new List<Product>(); Thread.Sleep(3000); Stopwatch swTask = new Stopwatch(); swTask.Start(); /*執行並行操做*/ Parallel.Invoke(SetProcuct1_500, SetProcuct2_500, SetProcuct3_500, SetProcuct4_500); swTask.Stop(); Console.WriteLine("500條數據 並行編程所耗時間:" + swTask.ElapsedMilliseconds); ProductList = new List<Product>(); Thread.Sleep(3000);/*防止並行操做 與 順序操做衝突*/ Stopwatch sw = new Stopwatch(); sw.Start(); SetProcuct1_500(); SetProcuct2_500(); SetProcuct3_500(); SetProcuct4_500(); sw.Stop(); Console.WriteLine("500條數據 順序編程所耗時間:" + sw.ElapsedMilliseconds); ProductList = new List<Product>(); Thread.Sleep(3000); swTask.Restart(); /*執行並行操做*/ Parallel.Invoke(() => SetProcuct1_10000(), () => SetProcuct2_10000(), () => SetProcuct3_10000(), () => SetProcuct4_10000()); swTask.Stop(); Console.WriteLine("10000條數據 並行編程所耗時間:" + swTask.ElapsedMilliseconds); ProductList = new List<Product>(); Thread.Sleep(3000); sw.Restart(); SetProcuct1_10000(); SetProcuct2_10000(); SetProcuct3_10000(); SetProcuct4_10000(); sw.Stop(); Console.WriteLine("10000條數據 順序編程所耗時間:" + sw.ElapsedMilliseconds); Console.ReadLine(); } private static void SetProcuct1_500() { for (int index = 1; index < 500; index++) { Product model = new Product(); model.Category = "Category" + index; model.Name = "Name" + index; model.SellPrice = index; ProductList.Add(model); } Console.WriteLine("SetProcuct1 執行完成"); } private static void SetProcuct2_500() { for (int index = 500; index < 1000; index++) { Product model = new Product(); model.Category = "Category" + index; model.Name = "Name" + index; model.SellPrice = index; ProductList.Add(model); } Console.WriteLine("SetProcuct2 執行完成"); } private static void SetProcuct3_500() { for (int index = 1000; index < 2000; index++) { Product model = new Product(); model.Category = "Category" + index; model.Name = "Name" + index; model.SellPrice = index; ProductList.Add(model); } Console.WriteLine("SetProcuct3 執行完成"); } private static void SetProcuct4_500() { for (int index = 2000; index < 3000; index++) { Product model = new Product(); model.Category = "Category" + index; model.Name = "Name" + index; model.SellPrice = index; ProductList.Add(model); } Console.WriteLine("SetProcuct4 執行完成"); } private static void SetProcuct1_10000() { for (int index = 1; index < 20000; index++) { Product model = new Product(); model.Category = "Category" + index; model.Name = "Name" + index; model.SellPrice = index; ProductList.Add(model); } Console.WriteLine("SetProcuct1 執行完成"); } private static void SetProcuct2_10000() { for (int index = 20000; index < 40000; index++) { Product model = new Product(); model.Category = "Category" + index; model.Name = "Name" + index; model.SellPrice = index; ProductList.Add(model); } Console.WriteLine("SetProcuct2 執行完成"); } private static void SetProcuct3_10000() { for (int index = 40000; index < 60000; index++) { Product model = new Product(); model.Category = "Category" + index; model.Name = "Name" + index; model.SellPrice = index; ProductList.Add(model); } Console.WriteLine("SetProcuct3 執行完成"); } private static void SetProcuct4_10000() { for (int index = 60000; index < 80000; index++) { Product model = new Product(); model.Category = "Category" + index; model.Name = "Name" + index; model.SellPrice = index; ProductList.Add(model); } Console.WriteLine("SetProcuct4 執行完成"); } } class Product { public string Name { get; set; } public string Category { get; set; } public int SellPrice { get; set; } }
圖中咱們能夠看出利用 Parallel.Invoke編寫的併發執行代,它的併發執行順序也是不定的。
可是所執行的時間上比不採用並行編程所耗的時間差很少。
這是由於咱們在並行編程中操做了共享資源 ProductList ,若是我把代碼作出如下修改,採用並行編程的好處就顯現出來了。
class Program { /* coder:釋迦苦僧 * 沒有特定的執行順序 * 示例中 基於電腦配置 採用了4個方法的並行編程 * Parallel.Invoke 首先會嘗試並行啓動4個方法,充分利用一個或多個物理處理器所提供的多個邏輯內核 * 可是在實際的並行執行中,至少要有4個邏輯內核才能知足4個方法的並行運行 * 若是有個或者多個邏輯內核處於繁忙狀態,那麼底層的調度邏輯可能會延遲某些方法的初始化執行 * 經過Parallel.Invoke編寫的併發執行代碼必定不能依賴與特定的執行順序,由於它的併發執行順序也是不定的。 */ static void Main(string[] args) { Thread.Sleep(3000); Stopwatch swTask = new Stopwatch(); swTask.Start(); /*執行並行操做*/ Parallel.Invoke(SetProcuct1_500, SetProcuct2_500, SetProcuct3_500, SetProcuct4_500); swTask.Stop(); Console.WriteLine("500條數據 並行編程所耗時間:" + swTask.ElapsedMilliseconds); Thread.Sleep(3000);/*防止並行操做 與 順序操做衝突*/ Stopwatch sw = new Stopwatch(); sw.Start(); SetProcuct1_500(); SetProcuct2_500(); SetProcuct3_500(); SetProcuct4_500(); sw.Stop(); Console.WriteLine("500條數據 順序編程所耗時間:" + sw.ElapsedMilliseconds); Thread.Sleep(3000); swTask.Restart(); /*執行並行操做*/ Parallel.Invoke(() => SetProcuct1_10000(), () => SetProcuct2_10000(), () => SetProcuct3_10000(), () => SetProcuct4_10000()); swTask.Stop(); Console.WriteLine("10000條數據 並行編程所耗時間:" + swTask.ElapsedMilliseconds); Thread.Sleep(3000); sw.Restart(); SetProcuct1_10000(); SetProcuct2_10000(); SetProcuct3_10000(); SetProcuct4_10000(); sw.Stop(); Console.WriteLine("10000條數據 順序編程所耗時間:" + sw.ElapsedMilliseconds); Console.ReadLine(); } private static void SetProcuct1_500() { List<Product> ProductList = new List<Product>(); for (int index = 1; index < 500; index++) { Product model = new Product(); model.Category = "Category" + index; model.Name = "Name" + index; model.SellPrice = index; ProductList.Add(model); } Console.WriteLine("SetProcuct1 執行完成"); } private static void SetProcuct2_500() { List<Product> ProductList = new List<Product>(); for (int index = 500; index < 1000; index++) { Product model = new Product(); model.Category = "Category" + index; model.Name = "Name" + index; model.SellPrice = index; ProductList.Add(model); } Console.WriteLine("SetProcuct2 執行完成"); } private static void SetProcuct3_500() { List<Product> ProductList = new List<Product>(); for (int index = 1000; index < 2000; index++) { Product model = new Product(); model.Category = "Category" + index; model.Name = "Name" + index; model.SellPrice = index; ProductList.Add(model); } Console.WriteLine("SetProcuct3 執行完成"); } private static void SetProcuct4_500() { List<Product> ProductList = new List<Product>(); for (int index = 2000; index < 3000; index++) { Product model = new Product(); model.Category = "Category" + index; model.Name = "Name" + index; model.SellPrice = index; ProductList.Add(model); } Console.WriteLine("SetProcuct4 執行完成"); } private static void SetProcuct1_10000() { List<Product> ProductList = new List<Product>(); for (int index = 1; index < 20000; index++) { Product model = new Product(); model.Category = "Category" + index; model.Name = "Name" + index; model.SellPrice = index; ProductList.Add(model); } Console.WriteLine("SetProcuct1 執行完成"); } private static void SetProcuct2_10000() { List<Product> ProductList = new List<Product>(); for (int index = 20000; index < 40000; index++) { Product model = new Product(); model.Category = "Category" + index; model.Name = "Name" + index; model.SellPrice = index; ProductList.Add(model); } Console.WriteLine("SetProcuct2 執行完成"); } private static void SetProcuct3_10000() { List<Product> ProductList = new List<Product>(); for (int index = 40000; index < 60000; index++) { Product model = new Product(); model.Category = "Category" + index; model.Name = "Name" + index; model.SellPrice = index; ProductList.Add(model); } Console.WriteLine("SetProcuct3 執行完成"); } private static void SetProcuct4_10000() { List<Product> ProductList = new List<Product>(); for (int index = 60000; index < 80000; index++) { Product model = new Product(); model.Category = "Category" + index; model.Name = "Name" + index; model.SellPrice = index; ProductList.Add(model); } Console.WriteLine("SetProcuct4 執行完成"); } } class Product { public string Name { get; set; } public string Category { get; set; } public int SellPrice { get; set; } }
我將每一個方法中的資源隔離,性能顯而易見。
可是在操做500條數據時,顯然採用並行操做並不明智,並行所帶來的損耗比較大,在實際的開發中,仍是要注意下是否有必要進行並行編程。
Parallel.For
將for循環替換成Parallel.For,並採用適合這個新方法的參數,就能夠對這個已有的for循環進行重構,使其可以充分利用並行化優點。
須要注意的是:1.Parallel.For不支持浮點數的步進,使用的是Int32或Int64,每一次迭代的時候加1
2.因爲循環體是並行運行,去迭代執行的順序沒法保證
下面貼代碼
class Program { /* coder:釋迦苦僧*/ static void Main(string[] args) { Thread.Sleep(3000); ForSetProcuct_100(); Thread.Sleep(3000); ParallelForSetProcuct_100(); Console.ReadLine(); } private static void ForSetProcuct_100() { Stopwatch sw = new Stopwatch(); sw.Start(); List<Product> ProductList = new List<Product>(); for (int index = 1; index < 100; index++) { Product model = new Product(); model.Category = "Category" + index; model.Name = "Name" + index; model.SellPrice = index; ProductList.Add(model); Console.WriteLine("for SetProcuct index: {0}", index); } sw.Stop(); Console.WriteLine("for SetProcuct 10 執行完成 耗時:{0}", sw.ElapsedMilliseconds); } private static void ParallelForSetProcuct_100() { Stopwatch sw = new Stopwatch(); sw.Start(); List<Product> ProductList = new List<Product>(); Parallel.For(1, 100, index => { Product model = new Product(); model.Category = "Category" + index; model.Name = "Name" + index; model.SellPrice = index; ProductList.Add(model); Console.WriteLine("ForSetProcuct SetProcuct index: {0}", index); }); sw.Stop(); Console.WriteLine("ForSetProcuct SetProcuct 20000 執行完成 耗時:{0}", sw.ElapsedMilliseconds); } } class Product { public string Name { get; set; } public string Category { get; set; } public int SellPrice { get; set; } }
由圖中咱們能夠看出,使用Parallel.For所迭代的順序是沒法保證的。
Parallel.ForEach
Parallel.ForEach提供一個並行處理一組數據的機制,能夠利用一個範圍的整數做爲一組數據,而後經過一個自定義的分區器將這個範圍轉換爲一組數據塊,每一塊數據都經過循環的方式進行處理,而這些循環式並行執行的。
下面貼代碼:
class Program { /* coder:釋迦苦僧*/ static void Main(string[] args) { List<Product> ProductList =GetProcuctList(); Parallel.ForEach(ProductList, (model) => { Console.WriteLine(model.Name); }); Console.ReadLine(); } private static List<Product> GetProcuctList() { List<Product> result = new List<Product>(); for (int index = 1; index < 100; index++) { Product model = new Product(); model.Category = "Category" + index; model.Name = "Name" + index; model.SellPrice = index; result.Add(model); } return result; } } class Product { public string Name { get; set; } public string Category { get; set; } public int SellPrice { get; set; } }
ParallelLoopState
ParallelLoopState該實例提供瞭如下兩個方法用於中止 Parallel.For,Parallel.ForEach
Break-這個方法告訴並行循環應該在執行了當前迭代後儘快地中止執行。吐過調用Break時正在處理迭代100,那麼循環仍然會處理全部小於100的迭代。
Stop-這個方法告訴並行循環應該儘快中止執行,若是調用Stop時迭代100正在被處理,那麼循環沒法保證處理完全部小於100的迭代
下面貼代碼
class Program { /* coder:釋迦苦僧*/ static void Main(string[] args) { List<Product> productList = GetProcuctList_500(); Thread.Sleep(3000); Parallel.For(0, productList.Count, (i, loopState) => { if (i < 100) { Console.WriteLine("採用Stop index:{0}", i); } else { /* 知足條件後 儘快中止執行,沒法保證小於100的索引數據所有輸出*/ loopState.Stop(); return; } }); Thread.Sleep(3000); Parallel.For(0, productList.Count, (i, loopState) => { if (i < 100) { Console.WriteLine("採用Break index:{0}", i); } else { /* 知足條件後 儘快中止執行,保證小於100的索引數據所有輸出*/ loopState.Break(); return; } }); Thread.Sleep(3000); Parallel.ForEach(productList, (model, loopState) => { if (model.SellPrice < 10) { Console.WriteLine("採用Stop index:{0}", model.SellPrice); } else { /* 知足條件後 儘快中止執行,沒法保證知足條件的數據所有輸出*/ loopState.Stop(); return; } }); Thread.Sleep(3000); Parallel.ForEach(productList, (model, loopState) => { if (model.SellPrice < 10) { Console.WriteLine("採用Break index:{0}", model.SellPrice); } else { /* 知足條件後 儘快中止執行,保證知足條件的數據所有輸出*/ loopState.Break(); return; } }); Console.ReadLine(); } private static List<Product> GetProcuctList_500() { List<Product> result = new List<Product>(); for (int index = 1; index < 500; index++) { Product model = new Product(); model.Category = "Category" + index; model.Name = "Name" + index; model.SellPrice = index; result.Add(model); } return result; } }
由圖中能夠看出Break能夠保證輸出知足全部條件的數據,而Stop則沒法保證。
關於 Parallel 類提供的 Parallel.Invoke ,Parallel.For,Parallel.ForEach 的簡介入門到這,若有錯誤歡迎指正
做者:釋迦苦僧 出處:http://www.cnblogs.com/woxpp/p/3925094.html本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接。