C#並行,多執行緒程式設計並行集合和PLINQ的例項講解
並行演算法的出現,隨之而產生的也曾有了並行集合,及執行緒安全集合;微軟向的也算周到,沒有忘記linq,也推出了linq的並行版本,plinq - Parallel Linq。
一,並行集合 - 執行緒安全集合
平行計算使用的多個執行緒同時進行計算,所以要控制每個執行緒對資源的訪問,我們先來看一下平時常用的列表集合,在平行計算下的表現,新建一個控制檯應用程式,新增一個PEnumerable類(當然你也直接寫到主方法裡面測試,建議分開寫),寫如下方法:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.Concurrent;
namespace ThreadPool
{
public class PEnumerable
{
public static void ListWithParallel()
{
List<int> list = new List<int>();
Parallel.For(0, 10000, item =>
{
list.Add(item);
});
Console.WriteLine("List's count is {0}",list.Count());
}
}
}
看到結果中顯示的5851,但是我們迴圈的是10000次啊!怎麼結果不對呢?這是因為名單是非執行緒安全集合,意思就是說所有的執行緒都可以修改他的值。
下面我們來看下並行集合 - 執行緒安全集合,在System.Collections.Concurrent名稱空間中,首先來看一下ConcurrentBag泛型集合,其用法和列表類似,先來寫個方法測試一下:
public static void ConcurrentBagWithPallel()
{
ConcurrentBag<int> list = new ConcurrentBag<int>();
Parallel.For(0, 10000, item =>
{
list.Add(item);
});
Console.WriteLine("ConcurrentBag's count is {0}", list.Count());
}
可以看到,ConcurrentBag集合的結果是正確的下面我們修改程式碼看看ConcurrentBag裡面的資料到底是怎麼存放的,修改程式碼如下:
public static void ConcurrentBagWithPallel()
{
ConcurrentBag<int> list = new ConcurrentBag<int>();
Parallel.For(0, 10000, item =>
{
list.Add(item);
});
Console.WriteLine("ConcurrentBag's count is {0}", list.Count());
int n = 0;
foreach(int i in list)
{
if (n > 10)
break;
n++;
Console.WriteLine("Item[{0}] = {1}",n,i);
}
Console.WriteLine("ConcurrentBag's max item is {0}", list.Max());
}
可以看到,ConcurrentBag中的資料並不是按照順序排列的,順序是亂的,隨機的。我們平時使用的最大,首先,最後等LINQ方法都還有。其時分類似可列舉的用法,大家可以參考微軟的MSDN瞭解它的具體用法。
關於執行緒安全的集合還有很多,和我們平時用的集合都差不多,比如類似字典的ConcurrentDictionary,還有ConcurrentStack,ConcurrentQueue等。
二,並行Linq的用法及效能
1,進行AsParallel
前面瞭解了並行的對於和的foreach,今天就來看一下的LINQ的並行版本是怎麼樣吧為了測試,我們新增一個自定義類,程式碼如下?
public class Custom
{ public string Name { get; set; } public int Age { get; set; } public string Address { get; set; } }
寫如下測試程式碼:
public static void TestPLinq()
{
Stopwatch sw = new Stopwatch();
List<custom> customs = new List<custom>();
for (int i = 0; i < 2000000; i++)
{
customs.Add(new Custom() { Name = "Jack", Age = 21, Address = "NewYork" });
customs.Add(new Custom() { Name = "Jime", Age = 26, Address = "China" });
customs.Add(new Custom() { Name = "Tina", Age = 29, Address = "ShangHai" });
customs.Add(new Custom() { Name = "Luo", Age = 30, Address = "Beijing" });
customs.Add(new Custom() { Name = "Wang", Age = 60, Address = "Guangdong" });
customs.Add(new Custom() { Name = "Feng", Age = 25, Address = "YunNan" });
}
sw.Start();
var result = customs.Where<custom>(c => c.Age > 26).ToList();
sw.Stop();
Console.WriteLine("Linq time is {0}.",sw.ElapsedMilliseconds);
sw.Restart();
sw.Start();
var result2 = customs.AsParallel().Where<custom>(c => c.Age > 26).ToList();
sw.Stop();
Console.WriteLine("Parallel Linq time is {0}.", sw.ElapsedMilliseconds);
}
其實也就是加了一個進行AsParallel()方法,下面來看下執行結果:
public static void OrderByTest()
{
Stopwatch stopWatch = new Stopwatch();
List<custom> customs = new List<custom>();
for (int i = 0; i < 2000000; i++)
{
customs.Add(new Custom() { Name = "Jack", Age = 21, Address = "NewYork" });
customs.Add(new Custom() { Name = "Jime", Age = 26, Address = "China" });
customs.Add(new Custom() { Name = "Tina", Age = 29, Address = "ShangHai" });
customs.Add(new Custom() { Name = "Luo", Age = 30, Address = "Beijing" });
customs.Add(new Custom() { Name = "Wang", Age = 60, Address = "Guangdong" });
customs.Add(new Custom() { Name = "Feng", Age = 25, Address = "YunNan" });
}
stopWatch.Restart();
var groupByAge = customs.GroupBy(item => item.Age).ToList();
foreach (var item in groupByAge)
{
Console.WriteLine("Age={0},count = {1}", item.Key, item.Count());
}
stopWatch.Stop();
Console.WriteLine("Linq group by time is: " + stopWatch.ElapsedMilliseconds);
stopWatch.Restart();
var lookupList = customs.ToLookup(i => i.Age);
foreach (var item in lookupList)
{
Console.WriteLine("LookUP:Age={0},count = {1}", item.Key, item.Count());
}
stopWatch.Stop();
Console.WriteLine("LookUp group by time is: " + stopWatch.ElapsedMilliseconds);
}
執行結果如下:
ToLookup方法是將集合轉換成一個只讀集合,所以在大資料量分組時效能優於名單。大家可以查閱相關資料,這裡由於篇幅問題,不再細說。
相關文章
- 深入C#並行程式設計(1) -- 瞭解執行緒C#並行行程程式設計執行緒
- 26、多執行緒與並行執行緒並行
- C#多執行緒(四)並行程式設計篇之結構化C#執行緒並行行程程式設計
- Python程式和執行緒例項詳解Python執行緒
- C#多執行緒程式設計實戰1.1建立執行緒C#執行緒程式設計
- C#多執行緒程式設計-基元執行緒同步構造C#執行緒程式設計
- C#多執行緒開發-任務並行庫04C#執行緒並行
- Python並行程式設計(七):多程式的基本使用和與多執行緒的差異Python並行行程程式設計執行緒
- 掌握C#中的GUI多執行緒技巧:WinForms和WPF例項詳解C#GUI執行緒ORM
- 【Java多執行緒】執行緒安全的集合Java執行緒
- 多執行緒並行執行,然後彙總結果執行緒並行
- 從偽並行的 Python 多執行緒說起並行Python執行緒
- pytest(13)-多執行緒、多程式執行用例執行緒
- Qt中的多執行緒與執行緒池淺析+例項QT執行緒
- [短文速讀 -5] 多執行緒程式設計引子:程式、執行緒、執行緒安全執行緒程式設計
- 多執行緒程式設計基礎(一)-- 執行緒的使用執行緒程式設計
- Python並行程式設計(二):多執行緒鎖機制利用Lock與RLock實現執行緒同步Python並行行程程式設計執行緒
- python 多執行緒程式設計Python執行緒程式設計
- JavaScript多執行緒程式設計JavaScript執行緒程式設計
- Python多執行緒程式設計Python執行緒程式設計
- pytest多程式/多執行緒執行測試用例執行緒
- 多執行緒程式設計基礎(二)-- 執行緒池的使用執行緒程式設計
- java多執行緒程式設計:你真的瞭解執行緒中斷嗎?Java執行緒程式設計
- C#多執行緒(6):執行緒通知C#執行緒
- Java 多執行緒讀取檔案並統計詞頻 例項 出神入化的《ThreadPoolExecutor》Java執行緒thread
- Java並行流:一次搞定多執行緒程式設計難題,讓你的程式飛起來!Java並行執行緒程式設計
- Java多執行緒並行處理任務的實現Java執行緒並行
- 多執行緒和多執行緒同步執行緒
- [Java併發]執行緒的並行等待Java執行緒並行
- Java併發(一)----程式、執行緒、並行、併發Java執行緒並行
- 多執行緒程式設計ExecutorService用法執行緒程式設計
- 29. 多執行緒程式設計執行緒程式設計
- 深入淺出Win32多執行緒程式設計--之綜合例項Win32執行緒程式設計
- 多執行緒程式設計總結:一、認識多執行緒本質執行緒程式設計
- C#基礎之多執行緒講解C#執行緒
- Java多執行緒程式設計筆記10:單例模式Java執行緒程式設計筆記單例模式
- iOS多執行緒程式設計三:Operation和OperationQueueiOS執行緒程式設計
- Python的多程式和多執行緒Python執行緒