8天玩轉並行開發——第三天 plinq的使用

船頭尺發表於2021-09-09

   

   相信在.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  20 && n.Age  LoadData()
43     {
44         ConcurrentDictionary dic = new ConcurrentDictionary();
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:常用方法的使用

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 
23         {
24             Console.WriteLine(i.CreateTime);
25         });
26 
27         var query2 = (from n in dic.Values.AsParallel()
28                       where n.Age > 20 && n.Age 
34         {
35             Console.WriteLine(i.CreateTime);
36         });
37 
38         Console.Read();
39     }
40 
41     public static ConcurrentDictionary LoadData()
42     {
43         ConcurrentDictionary dic = new ConcurrentDictionary();
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 }

圖片描述

圖片描述

 

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 

 

4: 瞭解ParallelEnumerable類

   首先這個類是Enumerable的並行版本,提供了很多用於查詢實現的一組方法,截個圖,大家看看是不是很熟悉,要記住,他們都是並行的。

圖片描述

下面列舉幾個簡單的例子。

圖片描述

 1 class Program
 2 {
 3     static void Main(string[] args)
 4     {
 5         ConcurrentBag bag = new ConcurrentBag();
 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:“化簡”操作,我們對這些巨大的“鍵值對集合“進行分組,統計等等。

具體大家可以看看百科:

 

下面我舉個例子,用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 list = new List()
        {
            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 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; }
    }
}

圖片描述

圖片描述

 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/3016/viewspace-2806291/,如需轉載,請註明出處,否則將追究法律責任。

相關文章