C#并行編程之PLINQ(并行LINQ)
用于對(duì)內(nèi)存中的數(shù)據(jù)做并行運(yùn)算,也就是說其只支持 LINQ to Object 的并行運(yùn)算
一、AsParallel(并行化)
就是在集合后加個(gè)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個(gè)硬件線程。
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)時(shí)間:{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)時(shí)間:{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)了并行化。
二、指定并行度
這個(gè)我在前面文章也說過,為了不讓并行計(jì)算占用全部的硬件線程,或許可能要留一個(gè)線程做其他事情。
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類
首先這個(gè)類是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集合中元素個(gè)數(shù)有:{0}", bag.Count);
Console.WriteLine("list集合中元素個(gè)數(shù)總和為:{0}", list.Sum());
Console.WriteLine("list集合中元素最大值為:{0}", list.Max());
Console.WriteLine("list集合中元素第一個(gè)元素為:{0}", list.FirstOrDefault());四、plinq實(shí)現(xiàn)MapReduce算法
mapReduce是一個(gè)非常流行的編程模型,用于大規(guī)模數(shù)據(jù)集的并行計(jì)算,非常的牛X啊,記得mongodb中就用到了這個(gè)玩意。
- map: 也就是“映射”操作,可以為每一個(gè)數(shù)據(jù)項(xiàng)建立一個(gè)鍵值對(duì),映射完后會(huì)形成一個(gè)鍵值對(duì)的集合。
- reduce:“化簡(jiǎn)”操作,我們對(duì)這些巨大的“鍵值對(duì)集合“進(jìn)行分組,統(tǒng)計(jì)等等。
下面我舉個(gè)例子,用Mapreduce來實(shí)現(xiàn)一個(gè)對(duì)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},
};
//這里我們會(huì)對(duì)age建立一組鍵值對(duì)
var map = list.AsParallel().ToLookup(i => i.Age, count => 1);
//化簡(jiǎn)統(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; }
}
考慮一個(gè)簡(jiǎn)單的例子,現(xiàn)有一個(gè)容量為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)的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C#實(shí)現(xiàn)批量Word轉(zhuǎn)換Html的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用C#批量Word轉(zhuǎn)換Html的功能,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C#有一定的幫助,感興趣的小伙伴可以跟隨小編一起了解一下2022-12-12
深入理解c# checked unchecked 關(guān)鍵字
本篇文章是對(duì)c#中的checked unchecked 關(guān)鍵字進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
Unity Shader實(shí)現(xiàn)紋理遮罩效果
這篇文章主要為大家詳細(xì)介紹了Unity Shader實(shí)現(xiàn)紋理遮罩效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-04-04
理解C#編程中的靜態(tài)類和靜態(tài)成員以及密封類
這篇文章主要介紹了理解C#編程中的靜態(tài)類和靜態(tài)成員以及密封類,注意類成員的相關(guān)訪問限制和類的繼承問題,需要的朋友可以參考下2016-01-01

