C# 并行编程 之 PLINQ 基本使用

PLINQ Summary

LINQ (LINQ) Language Integrated Query 可以方便的查询并处理不同数据源的数据。PLINQ Parallel LINQ不光拥有LINQ的功能,还添加了并行操作的接口,以方便使用并提高效率。

更详细的信息: https://msdn.microsoft.com/zh-cn/library/dd460688(v=vs.110).aspx

一个简单的例子

用一个简单的例子足以说明PLINQ的使用。

简单的说明:

第一部分:先在一个文档中查询包含字母 “a”的单词首先使用 LINQ进行查询10000次,然后使用PLINQ进行同样的测试,看看效率有多少提高。 AsParallel() 是主要用到的接口。

第二部分:计算Short类型所有数字的和,同样测试两次使用LINQ和PLINQ。

第三部分:测试PLINQ的查找排序功能。使用的接口分别为AsOrdered()和orderby

AsOrdered:保持数据在数据源中的顺序不变。

orderby:按用户指定的顺序进行排序,升序/降序

示例程序:

using System;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Linq;
using System.IO;

namespace Sample6_1_plink_basic
{
    class Program
    {
        static int SumDefault(int[] array)
        {
            return array.Sum();
        }

        static int SumAsParallel(int[] array)
        {
            return array.AsParallel().Sum();
        }

        static string[] words = { "Day", "Car", "Land", "Road", "Sea", "Mountain", "River"};

        static void Main(string[] args)
        {
            var customers = System.IO.File.ReadAllLines(@"D:\testdir\CSParallel_Program\Sample6-1 plink basic\target.txt");
            int nCounter = 0;
            Console.WriteLine("============================================================");
            Console.WriteLine("TEST NORMAL LINQ");
            Console.WriteLine("============================================================");
            var swatchpn = Stopwatch.StartNew();

            for (int i = 0; i < 10000; i++)
            {
                var normalkeyLetters = from line in customers
                                       let keys = line.Split(‘ ‘)
                                       from key in keys
                                       where (key.Contains(‘a‘))
                                       select key;

                var normalkeyList = normalkeyLetters.ToList();
                nCounter = normalkeyList.Count();
            }

            swatchpn.Stop();
            Console.WriteLine("Word with letter a = {0}", nCounter);
            Console.WriteLine("LINQ Use Time: {0}", swatchpn.Elapsed);

            Console.WriteLine("\n\n");
            Console.WriteLine("============================================================");
            Console.WriteLine("TEST PARALLEL LINQ");
            Console.WriteLine("============================================================");
            nCounter = 0;
            var swatchp = Stopwatch.StartNew();

            for (int i = 0; i < 10000; i++)
            {

                var keyLetters = from line in customers.AsParallel()
                                 let keys = line.Split(‘ ‘)
                                 from key in keys.AsParallel()
                                 where (key.Contains(‘a‘))
                                 select key;

                var keyList = keyLetters.ToList();
                nCounter = keyList.Count();
            }

            swatchp.Stop();
            Console.WriteLine("Word with letter a = {0}", nCounter);
            Console.WriteLine("PLINQ Use Time: {0}", swatchp.Elapsed);

            // Generate array.
            int[] array = Enumerable.Range(0, short.MaxValue).ToArray();
            const int m = 10000;
            var s1 = Stopwatch.StartNew();
            for (int i = 0; i < m; i++)
            {
                SumDefault(array);
            }
            s1.Stop();

            var s2 = Stopwatch.StartNew();
            for (int i = 0; i < m; i++)
            {
                SumAsParallel(array);
            }
            s2.Stop();
            Console.WriteLine("\n\n");
            Console.WriteLine("============================================================");
            Console.WriteLine("CALCULATE SUMMARY TEST");
            Console.WriteLine("============================================================");
            Console.WriteLine("Default Summary: " + ((double)(s1.Elapsed.TotalMilliseconds * 1000000) / m).ToString("0.00 ns"));
            Console.WriteLine("Parallel Summary: " + ((double)(s2.Elapsed.TotalMilliseconds * 1000000) /m).ToString("0.00 ns"));

            Console.WriteLine("\n\n");
            Console.WriteLine("============================================================");
            Console.WriteLine("Parallel ASOrder Test");
            Console.WriteLine("============================================================");
            var orderwords = from word in words.AsParallel().AsOrdered()
                             where (word.Contains(‘a‘))
                             select word;

            var orderletterList = orderwords.ToList();
            for (int i = 0; i < orderletterList.Count; i++)
            {
                Console.WriteLine(orderletterList[i]);
            }

            Console.WriteLine("\n\n");
            Console.WriteLine("============================================================");
            Console.WriteLine("Parallel OrderBy Test");
            Console.WriteLine("============================================================");
            var orderbywords = from word in words.AsParallel()
                             where (word.Contains(‘a‘))
                             orderby word ascending
                             select word;

            var orderbyletterList = orderbywords.ToList();
            for (int i = 0; i < orderbyletterList.Count; i++)
            {
                Console.WriteLine(orderbyletterList[i]);
            }

            Console.ReadKey();
        }
    }
}

测试结果:

测试其实运行过多次,关于单词的测试LINQ的结果在32至34秒,PLINQ大概在16至19秒,大约有50%的提升。

关于PLINQ中的数据分区

PLINQ使用多个任务对同一个数据源进行处理,然后汇总,使得效率提高。但并行执行的任务应该处理数据的哪个部分,怎样对数据进行合理的划分,并且分配给任务是很重要的,它会严重的影响效率。但开发者并不太可能去真正的控制PLINQ去采用哪种分区方式,了解一下它的内部机理在优化程序性能时会有一定的帮助。

PLINQ中有四种数据的划分方式:

  • 范围划分:用于可索引的数据源,例如数组和列表。PLINQ会查找数据源的IList接口,如果找到了,它就会采取范围据划分方式,将数据分解为与可用的逻辑内核数目相等的分区。PLINQ可以确切的知道数据规模,而且可以直接访问其中的任意元素。

  • 数据块划分:适用于任何数据源,用于不可索引的数据,不同任务此时得到的是数据块,块的大小可能不一样。

  • 交错式分区:这种方式对在数据源顶部对数据项进行处理的情况进行了优化。当查询包括SkipWhile和TakeWhile时会采用这种方式。此时每个任务对应的是一小组数据(简称条纹)。任务通过简单的计算可以判断出数据对应的条纹,所以任务间并不需要同步。

  • 散列分区:主要针对数据比较进行了优化。它在数据和任务间建立了通道,带有相同散列码的数据项会被发送到同一个任务中,这样有可能的匹配便会在一个数据分区中,从而简化了比较的过程,减少了不同任务间的数据共享。采用这种方式时分发数据时可能会有较大的开销,但数据比较时效率会提高。
时间: 2024-12-12 15:30:21

C# 并行编程 之 PLINQ 基本使用的相关文章

C# 并行编程 之 PLINQ 规约操作和聚合函数

概要 PLINQ可以简化对一个序列或一个组中所有成员应用同一个函数的过程,这个过程称之为规约操作.类似Sum()函数就是一个规约操作.PLINQ提供一个可重载Aggregate的接口,这里用户可以定义自己的规约函数. 规约操作是对每一个成员进行的操作,当操作完成后有可能需要将操作结果进行汇总得到一个最终的结果,这个就是聚合的概念. 规约操作 示例中要求计算 1 到 50000000中能被5整除的数除以PI以后得到的平均数.它可以用LINQ完成,也可以用PLINQ完成. 代码示例: using S

C#中的多线程 - 并行编程 z

原文:http://www.albahari.com/threading/part5.aspx 专题:C#中的多线程 1并行编程Permalink 在这一部分,我们讨论 Framework 4.0 加入的多线程 API,它们可以充分利用多核处理器. 并行 LINQ(Parallel LINQ)或称为 PLINQ Parallel类 任务并行(task parallelism)构造 SpinLock 和 SpinWait 这些 API 可以统称为 PFX(Parallel Framework,并行

5天玩转C#并行和多线程编程 —— 第二天 并行集合和PLinq

在上一篇博客5天玩转C#并行和多线程编程 —— 第一天 认识Parallel中,我们学习了Parallel的用法.并行编程,本质上是多线程的编程,那么当多个线程同时处理一个任务的时候,必然会出现资源访问问题,及所谓的线程安全.就像现实中,我们开发项目,就是一个并行的例子,把不同的模块分给不同的人,同时进行,才能在短的时间内做出大的项目.如果大家都只管自己写自己的代码,写完后发现合并不到一起,那么这种并行就没有了意义. 并行算法的出现,随之而产生的也就有了并行集合,及线程安全集合:微软向的也算周到

C#并行编程-PLINQ:声明式数据并行

原文:C#并行编程-PLINQ:声明式数据并行 背景 通过LINQ可以方便的查询并处理不同的数据源,使用Parallel LINQ (PLINQ)来充分获得并行化所带来的优势. PLINQ不仅实现了完整的LINQ操作符,而且还添加了一些用于执行并行的操作符,与对应的LINQ相比,通过PLINQ可以获得明显的加速,但是具体的加速效果还要取决于具体的场景,不过在并行化的情况下一段会加速. 如果一个查询涉及到大量的计算和内存密集型操作,而且顺序并不重要,那么加速会非常明显,然而,如果顺序很重要,那么加

C#并行编程 z

目录 C#并行编程-相关概念 C#并行编程-Parallel C#并行编程-Task C#并行编程-并发集合 C#并行编程-线程同步原语 C#并行编程-PLINQ:声明式数据并行 背景 基于任务的程序设计.命令式数据并行和任务并行都要求能够支持并发更新的数组.列表和集合. 在.NET Framework 4 以前,为了让共享的数组.列表和集合能够被多个线程更新,需要添加复杂的代码来同步这些更新操作. 如您需要编写一个并行循环,这个循环以无序的方式向一个共享集合中添加元素,那么必须加入一个同步机制

.Net并行编程系列之一:并行基础

现在普通PC平台上面多核处理器的普及,让我们领教了能够利用多核进行并行计算的软件的处理能力,同时继承更多地核心正是当前处理器发展的趋势. 但是作为一个.NET开发人员,是否有时候会发现你的程序占用了其中一个核心的大部分运行时间,甚至达到了100%,除了继续优化处理问题的算法. 那么还有方法能够利用CPU的其它核心为你的应用程序所用么?答案是显然可以的. 你所要做的,就是把应用程序的任务分割成块,使各块在同一时间运行. .Net 4.0引入了一种新的编程模型,结合VS2010使得开发并行应用程序变

理解并行编程

并行编程从业务实现的角度可分为数据并行与任务并行,也就是要解决的问题是以数据为核心还是以要处理的事情为核心.基于任务的并行编程模型TPL(任务并行库)是从业务角度实现的并行模型,它以System.Threading.Tasks命名空间下的Parallel类为实现核心类,优点是不需要我们考虑不同的硬件差异,只需要重点关注所实现的任务. 1.任务并行库TPL TPL主要包括数据并行和任务并行,无论是数据并行还是任务并行,都可以使用并行查询PLINQ提高数据查询的效率.数据并行是对数据集合中的元素同时

.NET并行编程1 -

设计模式--.net并行编程,清华大学出版的中译本. 相关资源地址主页面: http://parallelpatterns.codeplex.com/ 代码下载: http://parallelpatterns.codeplex.com/releases/view/50473 书籍在线地址: https://msdn.microsoft.com/en-us/library/ff963553.aspx 使用并行编程的一些示例: https://code.msdn.microsoft.com/Par

.NET 4.0 任务和并行编程系列

8天玩转并行开发 8天玩转并行开发——第一天 Parallel的使用 8天玩转并行开发——第二天 Task的使用 8天玩转并行开发——第三天 plinq的使用 8天玩转并行开发——第四天 同步机制(上) 8天玩转并行开发——第五天 同步机制(下) 8天玩转并行开发——第六天 异步编程模型 8天玩转并行开发——第七天 简要分析任务与线程池 8天玩转并行开发——第八天 用VS性能向导解剖你的程序 并行编程系列 .NET 4 并行(多核)编程系列之一入门介绍 .NET 4 并行(多核)编程系列之二 从