8天玩转并行开发——第三天 plinq的使用
相信在.net平台下,我们都玩过linq,是的,linq让我们的程序简洁优美,简直玩的是爱不释手,但是传统的linq只是串行代码,在并行的
年代如果linq不支持并行计算那该是多么遗憾的事情啊。
当然linq有很多种方式,比如linq to sql ,xml,object 等等,如果要将linq做成并行还是很简单的,这里我就举一个比较实际一点的例子,
我们知道为了更快的响应用户操作,码农们想尽了各种办法,绞尽了脑汁,其中有一个办法就是将数据库数据预加载到内存中,然后通过各种
数据结构的手段来加速CURD,是的,比如一个排序地球人只能做到N(lgN),那么如果我还想再快一点的话该怎么办呢?那么现在的并行就能发
挥巨大的优势,尤其是现在的服务器配置都是在8个硬件线程的情况下,你简直会狂笑好几天啊,好,不乱扯了。
1:AsParallel(并行化)
下面我们模拟给ConcurrentDictionary灌入1500w条记录,看看串行和并行效率上的差异,注意我的老爷机是2个硬件线程。

1 using System;
2 using System.Threading;
3 using System.Threading.Tasks;
4 using System.Diagnostics;
5 using System.Collections.Concurrent;
6 using System.Collections.Generic;
7
8 using System.Linq;
9
10 class Program
11 {
12 static void Main(string[] args)
13 {
14 var dic = LoadData();
15
16 Stopwatch watch = new Stopwatch();
17
18 watch.Start();
19
20 //串行执行
21 var query1 = (from n in dic.Values
22 where n.Age > 20 && n.Age < 25
23 select n).ToList();
24
25 watch.Stop();
26
27 Console.WriteLine("串行计算耗费时间:{0}", watch.ElapsedMilliseconds);
28
29 watch.Restart();
30
31 var query2 = (from n in dic.Values.AsParallel()
32 where n.Age > 20 && n.Age < 25
33 select n).ToList();
34
35 watch.Stop();
36
37 Console.WriteLine("并行计算耗费时间:{0}", watch.ElapsedMilliseconds);
38
39 Console.Read();
40 }
41
42 public static ConcurrentDictionary<int, Student> LoadData()
43 {
44 ConcurrentDictionary<int, Student> dic = new ConcurrentDictionary<int, Student>();
45
46 //预加载1500w条记录
47 Parallel.For(0, 15000000, (i) =>
48 {
49 var single = new Student()
50 {
51 ID = i,
52 Name = "hxc" + i,
53 Age = i % 151,
54 CreateTime = DateTime.Now.AddSeconds(i)
55 };
56 dic.TryAdd(i, single);
57 });
58
59 return dic;
60 }
61
62 public class Student
63 {
64 public int ID { get; set; }
65
66 public string Name { get; set; }
67
68 public int Age { get; set; }
69
70 public DateTime CreateTime { get; set; }
71 }
72 }


执行的结果还是比较震撼的,将近7倍,这是因为plinq的查询引擎会尽量利用cpu的所有硬件线程。
2:常用方法的使用
<1> orderby
有时候我们并不是简单的select一下就ok了,可能需要将结果进行orderby操作,并行化引擎会把要遍历的数据分区,然后在每个区上进行
orderby操作,最后来一个总的orderby,这里很像算法中的“归并排序”。


1 using System;
2 using System.Threading;
3 using System.Threading.Tasks;
4 using System.Diagnostics;
5 using System.Collections.Concurrent;
6 using System.Collections.Generic;
7
8 using System.Linq;
9
10 class Program
11 {
12 static void Main(string[] args)
13 {
14 var dic = LoadData();
15
16 var query1 = (from n in dic.Values.AsParallel()
17 where n.Age > 20 && n.Age < 25
18 select n).ToList();
19
20
21 Console.WriteLine("默认的时间排序如下:");
22 query1.Take(10).ToList().ForEach((i) =>
23 {
24 Console.WriteLine(i.CreateTime);
25 });
26
27 var query2 = (from n in dic.Values.AsParallel()
28 where n.Age > 20 && n.Age < 25
29 orderby n.CreateTime descending
30 select n).ToList();
31
32 Console.WriteLine("排序后的时间排序如下:");
33 query2.Take(10).ToList().ForEach((i) =>
34 {
35 Console.WriteLine(i.CreateTime);
36 });
37
38 Console.Read();
39 }
40
41 public static ConcurrentDictionary<int, Student> LoadData()
42 {
43 ConcurrentDictionary<int, Student> dic = new ConcurrentDictionary<int, Student>();
44
45 //预加载1500w条记录
46 Parallel.For(0, 15000000, (i) =>
47 {
48 var single = new Student()
49 {
50 ID = i,
51 Name = "hxc" + i,
52 Age = i % 151,
53 CreateTime = DateTime.Now.AddSeconds(i)
54 };
55 dic.TryAdd(i, single);
56 });
57
58 return dic;
59 }
60
61 public class Student
62 {
63 public int ID { get; set; }
64
65 public string Name { get; set; }
66
67 public int Age { get; set; }
68
69 public DateTime CreateTime { get; set; }
70 }
71 }


<2> sum(),average()等等这些聚合函数的效果跟orderby类型一样,都是实现了类型归并排序的效果,这里就不举例子了。
3:指定并行度,这个我在前面文章也说过,为了不让并行计算占用全部的硬件线程,或许可能要留一个线程做其他事情。
1 var query2 = (from n in dic.Values.AsParallel()
2 .WithDegreeOfParallelism(Environment.ProcessorCount - 1)
3 where n.Age > 20 && n.Age < 25
4 orderby n.CreateTime descending
5 select n).ToList();
4: 了解ParallelEnumerable类
首先这个类是Enumerable的并行版本,提供了很多用于查询实现的一组方法,截个图,大家看看是不是很熟悉,要记住,他们都是并行的。

下面列举几个简单的例子。

1 class Program
2 {
3 static void Main(string[] args)
4 {
5 ConcurrentBag<int> bag = new ConcurrentBag<int>();
6
7 var list = ParallelEnumerable.Range(0, 10000);
8
9 list.ForAll((i) =>
10 {
11 bag.Add(i);
12 });
13
14 Console.WriteLine("bag集合中元素个数有:{0}", bag.Count);
15
16 Console.WriteLine("list集合中元素个数总和为:{0}", list.Sum());
17
18 Console.WriteLine("list集合中元素最大值为:{0}", list.Max());
19
20 Console.WriteLine("list集合中元素第一个元素为:{0}", list.FirstOrDefault());
21
22 Console.Read();
23 }
24 }


5: plinq实现MapReduce算法
mapReduce是一个非常流行的编程模型,用于大规模数据集的并行计算,非常的牛X啊,记得mongodb中就用到了这个玩意。
map: 也就是“映射”操作,可以为每一个数据项建立一个键值对,映射完后会形成一个键值对的集合。
reduce:“化简”操作,我们对这些巨大的“键值对集合“进行分组,统计等等。
具体大家可以看看百科:http://baike.baidu.com/view/2902.htm
下面我举个例子,用Mapreduce来实现一个对age的分组统计。

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; class Program
{
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); //化简统计
var reduce = from IGrouping<int, int> singleMap
in map.AsParallel()
select new
{
Age = singleMap.Key,
Count = singleMap.Count()
}; ///最后遍历
reduce.ForAll(i =>
{
Console.WriteLine("当前Age={0}的人数有:{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; }
}
}


8天玩转并行开发——第三天 plinq的使用的更多相关文章
- 并行开发学习随笔1——plinq并行
这两天在看园友的文章 <8天玩转并行开发——第三天 plinq的使用> 对里面的第一个实例亲手实践了一下,发现了一点有意思的事情. 测试环境:.net 4.5 64位(如果是32位的,测试 ...
- 8天玩转并行开发——第八天 用VS性能向导解剖你的程序
原文 8天玩转并行开发——第八天 用VS性能向导解剖你的程序 最后一篇,我们来说说vs的“性能向导",通常我们调试程序的性能一般会使用Stopwatch,如果希望更加系统的了解程序,我们就需 ...
- 8天玩转并行开发——第二天 Task的使用
原文 8天玩转并行开发——第二天 Task的使用 在我们了解Task之前,如果我们要使用多核的功能可能就会自己来开线程,然而这种线程模型在.net 4.0之后被一种称为基于 “任务的编程模型”所冲击, ...
- 8天玩转并行开发——第一天 Parallel的使用
转自:http://www.cnblogs.com/huangxincheng/archive/2012/04/02/2429543.html 随着多核时代的到来,并行开发越来越展示出它的强大威力,像 ...
- [转]8天玩转并行开发——第二天 Task的使用
在我们了解Task之前,如果我们要使用多核的功能可能就会自己来开线程,然而这种线程模型在.net 4.0之后被一种称为基于 “任务的编程模型”所冲击,因为task会比thread具有更小的性能开销,不 ...
- 并行开发 8.用VS性能向导解剖你的程序
原文:8天玩转并行开发——第八天 用VS性能向导解剖你的程序 最后一篇,我们来说说vs的“性能向导",通常我们调试程序的性能一般会使用Stopwatch,如果希望更加系统的了解程序,我们就需 ...
- 并行开发 1.Parallel
原文:8天玩转并行开发——第一天 Parallel的使用 随着多核时代的到来,并行开发越来越展示出它的强大威力,像我们这样的码农再也不用过多的关注底层线程的实现和手工控制, 要了解并行开发,需要先了解 ...
- 并行开发 2.plink
原文:8天玩转并行开发——第二天 Task的使用 在我们了解Task之前,如果我们要使用多核的功能可能就会自己来开线程,然而这种线程模型在.net 4.0之后被一种称为基于 “任务的编程模型”所冲击, ...
- 并行开发 2.task
原文:8天玩转并行开发——第二天 Task的使用 在我们了解Task之前,如果我们要使用多核的功能可能就会自己来开线程,然而这种线程模型在.net 4.0之后被一种称为基于 “任务的编程模型”所冲击, ...
随机推荐
- UVA 10341 Solve It 解方程 二分查找+精度
题意:给出一个式子以及里面的常量,求出范围为[0,1]的解,精度要求为小数点后4为. 二分暴力查找即可. e^(-n)可以用math.h里面的exp(-n)表示. 代码:(uva该题我老是出现Subm ...
- 饭卡------HDOJ杭电2546(还是01背包!!!!!!)
Problem Description 电子科大本部食堂的饭卡有一种非常诡异的设计,即在购买之前推断剩余金额. 假设购买一个商品之前,卡上的剩余金额大于或等于5元,就一定能够购买成功(即使购买后卡上剩 ...
- SQL查询各阶段的统计信息
我们经常会遇到各种分类统计问题,须要将这些结果一次显示出来.这次老师提出的要求是我想看60分下面多少人.60~70多少人,70~80多少人.80~90多少人,90~100多少人.他们曾 ...
- Automatic Preferred Max Layout Width is not available on iOS versions prior to 8.0
今天在真机调试低版本系统的时候出现如题类似Layout Max Width在ios 8 之前不适用的问题, 初步估计是autolayout 所导致的 查找资料解决方法如下: 将label下Preffe ...
- Visual Studio 创建和使用dll的方法
DLL是一个包含可由多个程序同时使用的代码和数据的库. DLL文件就是把一些函数导出来,然后在新程序中进行复用的过程. 第一部分:使用Visual Studio 2010进行DLL的制作 生成方法一: ...
- python成长之路——第二天
cpython:c解释器 .pyc(字节码)——机器码 jpython :java解释器 java字节码 ironpython :C#解释器 C#字节码 .... 上面的:编译完之后 ...
- Pencil OJ 01 开发的准备
操作系统 ubuntu-12.04.5-desktop-amd64.iso 基本应用 Node 0.12.7 MongoDB 3.0.4 Robomongo 0.8.4 Atom 参考资料 OJ hu ...
- 开源 免费 java CMS - FreeCMS1.9 职位管理
项目地址:http://code.google.com/p/freecms/ 职位管理 管理职位,实现招聘功能. 1. 职位管理 从左側管理菜单点击职位管理进入. 2. 加入职位 在职位列表下方点击& ...
- Poj 3246 Balanced Lineup(线段树基础)
依旧是线段树基础题 询问区间的最大值和最小值之差,只有询问,没有插入删除.继续理解基础线段树 #include <iostream> #include <algorithm> ...
- eclipse如何设置成保护眼的背景色
链接地址:http://jingyan.baidu.com/article/2a138328b5d9ea074a134fc7.html 长时间的使用eclipse开发会很累吧 设置一个保护眼睛的豆沙 ...