原文 8天玩转并行开发——第三天 plinq的使用

相信在.net平台下,我们都玩过linq,是的,linq让我们的程序简洁优美,简直玩的是爱不释手,但是传统的linq只是串行代码,在并行的

年代如果linq不支持并行计算那该是多么遗憾的事情啊。

当然linq有很多种方式,比如linq to sql ,xml,object 等等,如果要将linq做成并行还是很简单的,这里我就举一个比较实际一点的例子,

我们知道为了更快的响应用户操作,码农们想尽了各种办法,绞尽了脑汁,其中有一个办法就是将数据库数据预加载到内存中,然后通过各种

数据结构的手段来加速CURD,是的,比如一个排序地球人只能做到N(lgN),那么如果我还想再快一点的话该怎么办呢?那么现在的并行就能发

挥巨大的优势,尤其是现在的服务器配置都是在8个硬件线程的情况下,你简直会狂笑好几天啊,好,不乱扯了。

1:AsParallel(并行化)

下面我们模拟给ConcurrentDictionary灌入1500w条记录,看看串行和并行效率上的差异,注意我的老爷机是2个硬件线程。

  1. 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. 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. 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. 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的分组统计。

  1. using System;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Diagnostics;
    using System.Collections.Concurrent;
  2.  
  3. using System.Collections.Generic;
  4.  
  5. using System.Linq;
  6.  
  7. 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},
    };
  8.  
  9. //这里我们会对age建立一组键值对
    var map = list.AsParallel().ToLookup(i => i.Age, count => 1);
  10.  
  11. //化简统计
    var reduce = from IGrouping<int, int> singleMap
    in map.AsParallel()
    select new
    {
    Age = singleMap.Key,
    Count = singleMap.Count()
    };
  12.  
  13. ///最后遍历
    reduce.ForAll(i =>
    {
    Console.WriteLine("当前Age={0}的人数有:{1}人", i.Age, i.Count);
    });
    }
  14.  
  15. public class Student
    {
    public int ID { get; set; }
  16.  
  17. public string Name { get; set; }
  18.  
  19. public int Age { get; set; }
  20.  
  21. public DateTime CreateTime { get; set; }
    }
    }

8天玩转并行开发——第三天 plinq的使用的更多相关文章

  1. 并行开发学习随笔1——plinq并行

    这两天在看园友的文章 <8天玩转并行开发——第三天 plinq的使用> 对里面的第一个实例亲手实践了一下,发现了一点有意思的事情. 测试环境:.net 4.5 64位(如果是32位的,测试 ...

  2. 8天玩转并行开发——第八天 用VS性能向导解剖你的程序

    原文 8天玩转并行开发——第八天 用VS性能向导解剖你的程序 最后一篇,我们来说说vs的“性能向导",通常我们调试程序的性能一般会使用Stopwatch,如果希望更加系统的了解程序,我们就需 ...

  3. 8天玩转并行开发——第二天 Task的使用

    原文 8天玩转并行开发——第二天 Task的使用 在我们了解Task之前,如果我们要使用多核的功能可能就会自己来开线程,然而这种线程模型在.net 4.0之后被一种称为基于 “任务的编程模型”所冲击, ...

  4. 8天玩转并行开发——第一天 Parallel的使用

    转自:http://www.cnblogs.com/huangxincheng/archive/2012/04/02/2429543.html 随着多核时代的到来,并行开发越来越展示出它的强大威力,像 ...

  5. [转]8天玩转并行开发——第二天 Task的使用

    在我们了解Task之前,如果我们要使用多核的功能可能就会自己来开线程,然而这种线程模型在.net 4.0之后被一种称为基于 “任务的编程模型”所冲击,因为task会比thread具有更小的性能开销,不 ...

  6. 并行开发 8.用VS性能向导解剖你的程序

    原文:8天玩转并行开发——第八天 用VS性能向导解剖你的程序 最后一篇,我们来说说vs的“性能向导",通常我们调试程序的性能一般会使用Stopwatch,如果希望更加系统的了解程序,我们就需 ...

  7. 并行开发 1.Parallel

    原文:8天玩转并行开发——第一天 Parallel的使用 随着多核时代的到来,并行开发越来越展示出它的强大威力,像我们这样的码农再也不用过多的关注底层线程的实现和手工控制, 要了解并行开发,需要先了解 ...

  8. 并行开发 2.plink

    原文:8天玩转并行开发——第二天 Task的使用 在我们了解Task之前,如果我们要使用多核的功能可能就会自己来开线程,然而这种线程模型在.net 4.0之后被一种称为基于 “任务的编程模型”所冲击, ...

  9. 并行开发 2.task

    原文:8天玩转并行开发——第二天 Task的使用 在我们了解Task之前,如果我们要使用多核的功能可能就会自己来开线程,然而这种线程模型在.net 4.0之后被一种称为基于 “任务的编程模型”所冲击, ...

随机推荐

  1. [Swust OJ 1126]--神奇的矩阵(BFS,预处理,打表)

    题目链接:http://acm.swust.edu.cn/problem/1126/ Time limit(ms): 1000 Memory limit(kb): 65535 上一周里,患有XX症的哈 ...

  2. BZOJ 1858: [Scoi2010]序列操作( 线段树 )

    略恶心的线段树...不过只要弄清楚了AC应该不难.... ---------------------------------------------------------------- #inclu ...

  3. iOS 常用开源代码整理

    本文章不定期整理. 1.AFNetworking AFNetworking 采用 NSURLConnection + NSOperation, 主要方便与服务端 API 进行数据交换, 操作简单, 功 ...

  4. PHP5新语法学习

    Final标记方法,使其不能被子类重载:Final标记类,使其不能被继承. 连续引用返回的对象$obj->method()->method2(); __autoload()使用未定义的类的 ...

  5. HTML5新标签

    <article>标签定义外部的内容.比如来自一个外部的新闻提供者的一篇新的文章,或者来自 blog 的文本,或者是来自论坛的文本.亦或是来自其他外部源内容. HTML5:<arti ...

  6. FileDescriptor

    FileDescriptor 在java中的java.io包下面 public final class FileDescriptor { ... } 官方的解释: 文件描述符类的实例用作与基础机器有关 ...

  7. solrCloud+tomcat+zookeeper配置

    一.环境准备: Solr版本:4.7.0 下载地址:http://www.apache.org/dyn/closer.cgi/lucene/solr/4.7.0 Tomcat版本:6.0.39 下载地 ...

  8. This exception may occur if matchers are combined with raw values

    org.mockito.exceptions.misusing.InvalidUseOfMatchersException: Invalid use of argument matchers!3 ma ...

  9. 基于visual Studio2013解决算法导论之017查找第n小元素

     题目 查找第n小元素 解决代码及点评 #include <stdio.h> #include <stdlib.h> #include <malloc.h> ...

  10. Effective C++ Item 40 明智而审慎地使用多重继承

    本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 经验:多重继承比单一继承复杂.它可能导致新的歧义性,以及对 virtual 继承的须要 演示 ...