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,还有ConcurrentStack,ConcurrentQueue等。
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方法,写一个测试方法,代码如下:
{ 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. ***
*****************************************************
转载于:https://www.cnblogs.com/gangle/p/11578681.html