C#并行編程之PLINQ(并行LINQ)
用于對內(nèi)存中的數(shù)據(jù)做并行運(yùn)算,也就是說其只支持 LINQ to Object 的并行運(yùn)算
一、AsParallel(并行化)
就是在集合后加個AsParallel()。
例如:
var numbers = Enumerable.Range(0, 100); var result = numbers.AsParallel().AsOrdered().Where(i => i % 2 == 0); foreach (var i in result) Console.WriteLine(i);
下面我們模擬給ConcurrentDictionary灌入1500w條記錄,看看串行和并行效率上的差異,注意我的老爺機(jī)是2個硬件線程。
static void Main(string[] args) { var dic = LoadData(); Stopwatch watch = new Stopwatch(); watch.Start(); //串行執(zhí)行 var query1 = (from n in dic.Values where n.Age > 20 && n.Age < 25 select n).ToList(); watch.Stop(); Console.WriteLine("串行計(jì)算耗費(fèi)時間:{0}", watch.ElapsedMilliseconds); watch.Restart(); var query2 = (from n in dic.Values.AsParallel() where n.Age > 20 && n.Age < 25 select n).ToList(); watch.Stop(); Console.WriteLine("并行計(jì)算耗費(fèi)時間:{0}", watch.ElapsedMilliseconds); Console.Read(); } public static ConcurrentDictionary<int, Student> LoadData() { ConcurrentDictionary<int, Student> dic = new ConcurrentDictionary<int, Student>(); //預(yù)加載1500w條記錄 Parallel.For(0, 15000000, (i) => { var single = new Student() { ID = i, Name = "hxc" + i, Age = i % 151, CreateTime = DateTime.Now.AddSeconds(i) }; dic.TryAdd(i, single); }); return dic; } public class Student { public int ID { get; set; } public string Name { get; set; } public int Age { get; set; } public DateTime CreateTime { get; set; } }
orderby,sum(),average()等等這些聚合函數(shù)都是實(shí)現(xiàn)了并行化。
二、指定并行度
這個我在前面文章也說過,為了不讓并行計(jì)算占用全部的硬件線程,或許可能要留一個線程做其他事情。
var query2 = (from n in dic.Values.AsParallel().WithDegreeOfParallelism(Environment.ProcessorCount - 1) where n.Age > 20 && n.Age < 25 orderby n.CreateTime descending select n).ToList();
三、了解ParallelEnumerable類
首先這個類是Enumerable的并行版本,提供了很多用于查詢實(shí)現(xiàn)的一組方法,下圖為ParallelEnumerable類的方法,記住他們都是并行的。
ConcurrentBag<int> bag = new ConcurrentBag<int>(); var list = ParallelEnumerable.Range (0, 10000); list.ForAll((i) => { bag.Add(i); }); Console.WriteLine("bag集合中元素個數(shù)有:{0}", bag.Count); Console.WriteLine("list集合中元素個數(shù)總和為:{0}", list.Sum()); Console.WriteLine("list集合中元素最大值為:{0}", list.Max()); Console.WriteLine("list集合中元素第一個元素為:{0}", list.FirstOrDefault());
四、plinq實(shí)現(xiàn)MapReduce算法
mapReduce是一個非常流行的編程模型,用于大規(guī)模數(shù)據(jù)集的并行計(jì)算,非常的牛X啊,記得mongodb中就用到了這個玩意。
- map: 也就是“映射”操作,可以為每一個數(shù)據(jù)項(xiàng)建立一個鍵值對,映射完后會形成一個鍵值對的集合。
- reduce:“化簡”操作,我們對這些巨大的“鍵值對集合“進(jìn)行分組,統(tǒng)計(jì)等等。
下面我舉個例子,用Mapreduce來實(shí)現(xiàn)一個對age的分組統(tǒng)計(jì)。
static void Main(string[] args) { List<Student> list = new List<Student>() { new Student(){ ID=1, Name="jack", Age=20}, new Student(){ ID=1, Name="mary", Age=25}, new Student(){ ID=1, Name="joe", Age=29}, new Student(){ ID=1, Name="Aaron", Age=25}, }; //這里我們會對age建立一組鍵值對 var map = list.AsParallel().ToLookup(i => i.Age, count => 1); //化簡統(tǒng)計(jì) var reduce = from IGrouping<int, int> singleMap in map.AsParallel() select new { Age = singleMap.Key, Count = singleMap.Count() }; ///最后遍歷 reduce.ForAll(i => { Console.WriteLine("當(dāng)前Age={0}的人數(shù)有:{1}人", i.Age, i.Count); }); } public class Student { public int ID { get; set; } public string Name { get; set; } public int Age { get; set; } public DateTime CreateTime { get; set; } }
考慮一個簡單的例子,現(xiàn)有一個容量為1000000的單詞集,需要我們以降序列出其中出現(xiàn)次數(shù)超過100000的單詞(和其次數(shù))。Map過程,使用PLINQ將集合按單詞分組,這里使用了Lookup容器接口,它與Dictionary類似,但是提供的是鍵-值集映射;Reduce過程,使用PLINQ歸約查詢即可。
某一次運(yùn)行結(jié)果如下:
Word: you, Count: 142416
Word: van, Count: 115816
Word: next, Count: 110228
到此這篇關(guān)于C#并行編程之PLINQ(并行LINQ)的文章就介紹到這了。希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
VS2013創(chuàng)建Windows服務(wù)與調(diào)試服務(wù)的圖文方法
這篇文章主要介紹了VS2013創(chuàng)建Windows服務(wù)與調(diào)試服務(wù)的圖文方法,需要的朋友可以參考下2017-02-02深入解析C#設(shè)計(jì)模式編程中對建造者模式的運(yùn)用
這篇文章主要介紹了C#設(shè)計(jì)模式編程中對建造者模式的運(yùn)用,文中還介紹了在.NET框架下建造者模式編寫思路的實(shí)現(xiàn),需要的朋友可以參考下2016-02-02C#開發(fā)Winform控件之打開文件對話框OpenFileDialog類
這篇文章介紹了C#開發(fā)Winform控件之打開文件對話框OpenFileDialog類,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-02-02C#中DataSet轉(zhuǎn)化為實(shí)體集合類的方法
這篇文章主要介紹了C#中DataSet轉(zhuǎn)化為實(shí)體集合類的方法,是非常實(shí)用的技巧,需要的朋友可以參考下2014-10-10C#中的DataSet、string、DataTable、對象轉(zhuǎn)換成Json的實(shí)現(xiàn)代碼
這篇文章主要介紹了C#中的DataSet、string、DataTable、對象轉(zhuǎn)換成Json的實(shí)現(xiàn)代碼,需要的朋友可以參考下2014-09-09winform攔截關(guān)閉按鈕觸發(fā)的事件示例
這篇文章主要介紹了c# winform攔截關(guān)閉按鈕觸發(fā)的事件示例,大家參考使用吧2014-01-01