• C# 并行编程 PLINQ


    Parallel Linq的用法

    并行集合

      并行计算使用的多个线程同时进行计算,所以要控制每个线程对资源的访问,我们先来看一下平时常用的List<T>集合,在并行计算下的表现:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Collections.Concurrent;
    
    namespace ThreadPool
    {
       public class PEnumerable
       {
          public static void ListWithParallel()
          {
             List<int> list = new List<int>();
             Parallel.For(0, 10000, item =>
             {
                list.Add(item);
             });
             Console.WriteLine("List's count is {0}",list.Count());
          }
       }
    }
     

    看到结果中显示的5861,而不是我们循环的是10000次啊!怎么结果不对呢?这是因为List<T>是非线程安全集合,意思就是说所有的线程都可以修改他的值。

    下面我们来看下并行集合 —— 线程安全集合,在System.Collections.Concurrent命名空间中,首先来看一下ConcurrentBag<T>泛型集合,其用法和List<T>类似,先来写个方法测试一下:

     
          public static void ConcurrentBagWithPallel()
          {
             ConcurrentBag<int> list = new ConcurrentBag<int>();
             Parallel.For(0, 10000, item =>
             {
                list.Add(item);
             });
             Console.WriteLine("ConcurrentBag's count is {0}", list.Count());
          }
     

    可以看到,ConcurrentBag集合的结果是正确的,但ConcurrentBag中的数据并不是按照顺序排列的,顺序是乱的,随机的。我们平时使用的Max、First、Last等linq方法都还有。

    关于线程安全的集合还有很多,和我们平时用的集合都差不多,比如类似Dictionary的ConcurrentDictionary,还有ConcurrentStackConcurrentQueue等。

    AsParallel 方法

    前面了解了并行的For和foreach,今天就来看一下Linq的并行版本是怎么样吧?为了测试,我们添加一个Custom类,代码如下:

       public class Custom
       {
          public string Name { get; set; }
          public int Age { get; set; }
          public string Address { get; set; }
       }

     写如下测试代码:

          public static void TestPLinq()
          {
             Stopwatch sw = new Stopwatch();
             List<Custom> customs = new List<Custom>();
             for (int i = 0; i < 2000000; i++)
             {
                customs.Add(new Custom() { Name = "Jack", Age = 21, Address = "NewYork" });
                customs.Add(new Custom() { Name = "Jime", Age = 26, Address = "China" });
                customs.Add(new Custom() { Name = "Tina", Age = 29, Address = "ShangHai" });
                customs.Add(new Custom() { Name = "Luo", Age = 30, Address = "Beijing" });
                customs.Add(new Custom() { Name = "Wang", Age = 60, Address = "Guangdong" });
                customs.Add(new Custom() { Name = "Feng", Age = 25, Address = "YunNan" });
             }
    
             sw.Start();
             var result = customs.Where<Custom>(c => c.Age > 26).ToList();
             sw.Stop();
             Console.WriteLine("Linq time is {0}.",sw.ElapsedMilliseconds);
    
             sw.Restart();
             sw.Start();
             var result2 = customs.AsParallel().Where<Custom>(c => c.Age > 26).ToList();
             sw.Stop();
             Console.WriteLine("Parallel Linq time is {0}.", sw.ElapsedMilliseconds);
          }

    ToLookup方法

    在项目中,我们经常要对数据做处理,比如分组统计,我们知道在linq中也可以实现,今天来学习一下新的ToLookup方法,写一个测试方法,代码如下:

           public static void OrderByTest()
          {
             Stopwatch stopWatch = new Stopwatch();
             List<Custom> customs = new List<Custom>();
             for (int i = 0; i < 2000000; i++)
             {
                customs.Add(new Custom() { Name = "Jack", Age = 21, Address = "NewYork" });
                customs.Add(new Custom() { Name = "Jime", Age = 26, Address = "China" });
                customs.Add(new Custom() { Name = "Tina", Age = 29, Address = "ShangHai" });
                customs.Add(new Custom() { Name = "Luo", Age = 30, Address = "Beijing" });
                customs.Add(new Custom() { Name = "Wang", Age = 60, Address = "Guangdong" });
                customs.Add(new Custom() { Name = "Feng", Age = 25, Address = "YunNan" });
             }
    
             stopWatch.Restart();
             var groupByAge = customs.GroupBy(item => item.Age).ToList();
             foreach (var item in groupByAge)
             {
                Console.WriteLine("Age={0},count = {1}", item.Key, item.Count());
             }
             stopWatch.Stop();
    
             Console.WriteLine("Linq group by time is: " + stopWatch.ElapsedMilliseconds);
    
    
             stopWatch.Restart();
             var lookupList = customs.ToLookup(i => i.Age);
             foreach (var item in lookupList)
             {
                Console.WriteLine("LookUP:Age={0},count = {1}", item.Key, item.Count());
             }
             stopWatch.Stop();
             Console.WriteLine("LookUp group by time is: " + stopWatch.ElapsedMilliseconds);
          }

    ToLookup方法是将集合转换成一个只读集合,所以在大数据量分组时性能优于List.

    *****************************************************
    *** No matter how far you go, looking back is also necessary. ***
    *****************************************************
  • 相关阅读:
    AcRxClass::addX
    string.format("%s",name)
    strcmp 与 _tcscmp
    acedinitget
    判断实体的类型 相关操作
    accmcolor
    CAD类型转换
    图的存储结构及遍历
    并查集(Union/Find)
    设计模式--缺醒适配器模式
  • 原文地址:https://www.cnblogs.com/gangle/p/11578681.html
Copyright © 2020-2023  润新知