菜鳥學習并行編程,參考《C#并行編程高級教程.PDF》,如有錯誤,歡迎指正。
C#并行編程-相關概念
C#并行編程-Parallel
C#并行編程-Task
C#并行編程-并發集合
C#并行編程-線程同步原語
C#并行編程-PLINQ:聲明式數據并行
TPL中引入了一個新命名空間System.Threading.Tasks,在該命名空間下Task是主類,表示一個類的異步的并發的操作,創建并行代碼的時候不一定要直接使用Task類,在某些情況下可以直接使用Parallel靜態類(System.Threading.Tasks.Parallel)下所提供的方法,而不用底層的Task實例。
Parallel.Invoke
試圖將很多方法并行運行,如果傳入的是4個方法,則至少需要4個邏輯內核才能足以讓這4個方法并發運行,邏輯內核也稱為硬件線程。
需要注意的是: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; } }View Code
圖中我們可以看出利用 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.St
新聞熱點
疑難解答