• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

C#编程(六十三)----------并行LINQ

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

并行LINQ

.NET4在System.Linq命名空间中包含一个新类ParallelEnumerable,可以分解查询的工作使其分布在多个线程上.尽管Enumerable类给IEnumerable<T>接口定义了扩展方法,但ParallelEnumerable类的大多数扩展方法是ParallelQuery<TSource>类的扩展.一个重要的例外是AsParallel()方法,它扩展了IEnumerable<TSource>接口,返回ParallelQuery<TSource>类,所以正常的集合类可以以平行方式查询.

LINQ比较强大的是还提供了可并行处理的查询,这使得我们可以借助它来完成一些查询处理或处理并行操作.

 

 

先来说一下并行集合,并行计算使用的多个线程同时进行计算,所以要控制每个线程对资源的访问,我们先来看一下常用的List<T>集合,在并行计算下的表示:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

 

namespace 并行集合和LINQ

{

    class Program

    {

        static void Main(string[] args)

        {

            List<int> list = new List<int>();

            Parallel.For(0, 10000, item =>

                {

                    list.Add(item);

                }

                );

            Console.WriteLine("list的长度为 : {0}",list.Count());

            //多测试几次,就是说多运行几次

            /*

             * 从结构可以看出,我们的结构不是10000.这是为什么呢,这是因为List是费线程安全的

             * ,也就是说,任何线程都可以修改他的值

             */

            Console.ReadKey();

        }

    }

}

 

 

 

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

            ConcurrentBag<int> list =new ConcurrentBag<int>();

            Parallel.For(0, 10000, item =>

                {

                    list.Add(item);

                }

                );

            Console.WriteLine("ConcurrentBag的长度为 : {0}", list.Count());

            //不管运行几次,结果都是10000

 

分析一下,因为ConcurrentBag是线程安全的,所以每次结果都是正确的.

 

 

下面我们来修改代码看看ConcurrentBag里面的数据到底是怎样存放的,修改代码如下:

using System;

using System.Collections.Concurrent;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

 

namespace 并行集合和LINQ

{

    class Program

    {

        static void Main(string[] args)

        {

            ConcurrentBag<int> list =new ConcurrentBag<int>();

            Parallel.For(0, 10000, item =>

                {

                    list.Add(item);

                }

                );

            Console.WriteLine("ConcurrentBag的长度为 : {0}", list.Count());

            //不管运行几次,结果都是10000

            int n = 0;

            foreach (var item in list)

            {

                if (n>10)

                {

                    break;

                }

                n++;

                Console.WriteLine("Item[{0}] = {1}",n,item);//,多运行几次,观察这里的输出

            }

            Console.WriteLine("ConcurrentBag的最大长度为 : {0}",list.Max());

            Console.ReadKey();

        }

    }

}

 

 

分析:可以看到ConcurrentBag中的数据并不是按照顺序排列的,顺序是乱的,随机的.我们平时使用的Max,First,Last等LINQ方法都还有.其十分类似Enumerable的用法.

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

 

 

并行LINQ的用法和性能

1.AsParallel

案例:

using System;

using System.Collections.Concurrent;

using System.Collections.Generic;

using System.Diagnostics;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

 

namespace 并行集合和LINQ

{

    class Program

    {

        static void Main(string[] args)

        {

            Stopwatch sw = new Stopwatch();//需要添加命名空间 System.Threading.Tasks;

            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);

            Console.WriteLine("运行完毕");//这句话可能需要过一会才能出现

            Console.ReadKey();

        }

    }

    public class Custom

    {

        public string Name { get; set; }

        public int Age { get; set; }

        public string Address { get; set; }

    }

}

分析:多运行即便可以发现,添加了AsParallel()方法的速度差不多快了一倍.其实,AsParallel()这个方法可以应用与任何集合,包括List<T>集合,从而提高查询速度和系统性能。

 

2.GroupBy方法

在项目中,我们经常要对数据做处理,比如分组统计,我们知道在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);

 

            Console.WriteLine("运行完毕");//这句话可能需要过一会才能出现

            Console.ReadKey();

 

 

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


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
c#@符号后面对双引号转义发布时间:2022-07-14
下一篇:
微软是如何让我再次爱上.NetCore和C#的发布时间:2022-07-14
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap