并行编程之PLINQ

并行 LINQ (PLINQ) 是 LINQ 模式的并行实现。PLINQ 的主要用途是通过在多核计算机上以并行方式执行查询委托来加快 LINQ to Objects 查询的执行速度。与顺序 LINQ 查询一样,PLINQ 查询对任何内存中 IEnumerable 或 IEnumerable<(Of <(T>)>) 数据源进行操作,并推迟执行,这意味着在枚举查询之前不会开始执行这些操作。主要区别是 PLINQ 尝试充分利用系统中的所有处理器。它利用所有处理器的方法是,将数据源分成片段,然后在多个处理器上对单独工作线程上的每个片段并行执行查询。在许多情况下,并行执行意味着查询运行速度显著提高。

通过并行执行,PLINQ 通常只需向数据源添加 AsParallel 查询操作,即可在某些查询类型的旧版代码上获得显著的性能改进。但是,并行可能引入其自己的复杂性,因此并非所有查询操作在 PLINQ 中都运行得更快。事实上,并行降低了某些查询的速度。

System.Linq..::.ParallelEnumerable 类公开 PLINQ 的几乎所有功能。此类和 System.Linq 命名空间类型的其余部分一起编译到 System.Core.dll 程序集中。

1、选择使用模型

当您编写查询时,通过在数据源上调用 ParallelEnumerableAsParallel()()() 扩展方法来选择使用 PLINQ,如下面的示例所示。

var source = Enumerable.Range(1, 10000);

// Opt-in to PLINQ with AsParallel

var evenNums = from num in source.AsParallel()

where Compute(num) > 0

select num;

2、并行度

默认情况下,PLINQ 使用主机上的所有处理器,这些处理器的数量最多可达 64 个。通过使用 WithDegreeOfParallelism()()() 方法,可以指示 PLINQ 使用不多于指定数量的处理器。这在当您要确保计算机上运行的其他进程收到一定的 CPU 时间量时非常有用。下面的代码段将查询限制为最多使用两个处理器。

var query = from item in source.AsParallel().WithDegreeOfParallelism(2)

where Compute(item) > 42

select item;

3、总体工作的计算开销

为了实现加速,PLINQ 查询必须具有足够的适合并行工作来弥补开销。工作可表示为每个委托的计算开销与源集合中元素数量的乘积。假定某个操作可并行化,则它的计算开销越高,加速的可能性就越大。例如,如果某个函数执行花费的时间为 1 毫秒,则针对 1000 个元素进行的顺序查询将花费 1 秒来执行该操作,而在四核计算机上进行的并行查询可能只花费 250 毫秒。这样就产生了 750 毫秒的加速。如果该函数对于每个元素需要花费 1 秒来执行,则加速将为 750 秒。如果委托的开销很大,则对于源集合中的很少几个项,PLINQ 可能会提供明显的加速。相反,包含无关紧要委托的小型源集合通常不适合于 PLINQ。

在下面的示例中,queryA 可能适合于 PLINQ(假定其 Select 函数涉及大量工作)。queryB 可能不适合,原因是 Select 语句中没有足够的工作,并且并行化的开销将抵销大部分或全部加速。

var queryA = from num in source.AsParallel()

select ExpensiveFunction(num); //good for PLINQ

var queryB = from num in source.AsParallel()

where num % 2 > 0

select num; //not as good for PLINQ

4、PLINQ 何时选择顺序模式

PLINQ 将始终尝试至少按与查询以顺序方式运行同样的速度来执行查询。尽管 PLINQ 不会查看用户委托的计算开销有多高或输入源有多大,但它却会查找某些查询"形状"。具体而言,它将查找通常会导致查询在并行模式下运行更慢的查询运算符或运算符组合。如果找到此类形状,PLINQ 默认情况下会转而使用顺序模式。

但是,在衡量特定查询的性能后,您可能会确定该查询在并行模式下实际运行更快。在这些情况下,您可以通过 ParallelEnumerableWithExecutionMode()()() 方法使用 ParallelExecutionMode..::.ForceParallelism 标志,以指示 PLINQ 对查询进行并行化。有关更多信息,请参见如何:在 PLINQ 中指定执行模式。

下面的列表介绍了 PLINQ 默认情况下将按顺序模式执行的查询形状:

  • 包含 Select 子句、已建立索引的 Where 子句、已建立索引的 SelectMany 子句或 ElementAt 子句的查询(在排序或筛选运算符移除或重新排列了索引后)。
  • 包含 Take、TakeWhile、Skip、SkipWhile 运算符并且源序列中的索引未采用原始顺序的查询。
  • 包含 Zip 或 SequenceEquals 的查询,除非其中一个数据源具有按原始顺序排列的索引,并且另一个数据源可建立索引(即,数组或 IList(T))。
  • 包含 Concat 的查询,除非将其应用到可建立索引的数据源。
  • 包含 Reverse 的查询,除非应用到可建立索引的数据源。

5、PLINQ 中的顺序保留

下面的示例演示一个未排序的并行查询,该查询筛选与某个条件匹配的所有元素,而不会尝试以任何方式对结果进行排序。此查询不一定会生成源序列中满足条件的前1000 个城市,而是会生成满足条件的某一组 1000 个城市。您可以通过对源序列使用 AsOrdered()()() 运算符来启用顺序保留。然后,您可以稍后通过使用 AsUnOrdered()()() 方法在查询中禁用顺序保留。

var cityQuery = (from city in cities.AsParallel()

where city.Population > 10000

select city)

.Take(1000);

查询运算符和排序

下面的查询运算符将顺序保留引入查询的所有后续运算中,或直至调用 AsUnordered()()() 为止:

  • OrderBy()()()
  • OrderByDescending()()()
  • ThenBy()()()
  • ThenByDescending()()()

下面的 PLINQ 查询运算符在某些情况下可能要求经过排序的源序列生成正确的结果:

  • Reverse()()()
  • SequenceEquals()()()
  • TakeWhile()()()
  • SkipWhile()()()
  • Zip()()()

并行编程之PLINQ的更多相关文章

  1. .Net并行编程之二:并行循环

    本篇内容主要包括: 1.能够转化为并行循环的条件 2.并行For循环的用法:Parallel.For 3.并行ForEach的用法Parallel.ForEach 4.并行LINQ(PLINQ)的用法 ...

  2. Pthreads并行编程之spin lock与mutex性能对比分析(转)

    POSIX threads(简称Pthreads)是在多核平台上进行并行编程的一套常用的API.线程同步(Thread Synchronization)是并行编程中非常重要的通讯手段,其中最典型的应用 ...

  3. 并行编程之CountdownEvent的用法

    教程:http://blog.gkarch.com/threading/part5.html#the-parallel-class http://www.cnblogs.com/huangxinche ...

  4. 异步编程之Promise(3):拓展进阶

    异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...

  5. iOS 多线程编程之Grand Central Dispatch(GCD)

    介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其它的对称多处理系统的系统.这建立在任务并行运行的线程池模式的基础上的. 它 ...

  6. 深入浅出Cocoa多线程编程之 block 与 dispatch quene

    深入浅出 Cocoa 多线程编程之 block 与 dispatch quene 罗朝辉(http://www.cppblog.com/kesalin CC 许可,转载请注明出处 block 是 Ap ...

  7. python并发编程之multiprocessing进程(二)

    python的multiprocessing模块是用来创建多进程的,下面对multiprocessing总结一下使用记录. 系列文章 python并发编程之threading线程(一) python并 ...

  8. Python函数式编程之map()

    Python函数式编程之map() Python中map().filter().reduce()这三个都是应用于序列的内置函数. 格式: map(func, seq1[, seq2,…]) 第一个参数 ...

  9. [Cocoa]深入浅出Cocoa多线程编程之 block 与 dispatch quene

    深入浅出 Cocoa 多线程编程之 block 与 dispatch quene 罗朝辉(http://www.cppblog.com/kesalin CC 许可,转载请注明出处 block 是 Ap ...

随机推荐

  1. (大数据工程师学习路径)第一步 Linux 基础入门----数据流重定向

    介绍 开始对重定向这个概念感到些许陌生,但通过前面的课程中多次见过>或>>操作了,并知道他们分别是将标准输出导向一个文件或追加到一个文件中.这其实就是重定向,将原本输出到标准输出的数 ...

  2. java 科学计算库

    stackoverflow 上的讨论, 其中不乏lib的作者... http://stackoverflow.com/questions/529457/performance-of-java-matr ...

  3. android layout物业介绍

    android:id 为控件指定对应的ID android:text 指定控件其中显示的文字,须要注意的是,这里尽量使用strings.xml文件其中的字符串 android:gravity 指定Vi ...

  4. POJ 2352 &amp;&amp; HDU 1541 Stars (树状数组)

    一開始想,总感觉是DP,但是最后什么都没想到.还暴力的交了一发. 然后開始写线段树,结果超时.感觉自己线段树的写法有问题.改天再写.先把树状数组的写法贴出来吧. ~~~~~~~~~~~~~~~~~~~ ...

  5. Win8.1 Update如何禁用OneDrive同步服务

    原文 Win8.1 Update如何禁用OneDrive同步服务 上周,IT之家为爱好者分享Win8.1 Update如何提高OneDrive上传速度教程.但是,由于国内特殊网络环境,导致微软OneD ...

  6. html转换为纯文本,支持撇号

    /// <summary> /// html转换为纯文本 /// </summary> /// <param name="source">< ...

  7. Swift语言指南(六)--可选值

    原文:Swift语言指南(六)--可选值 在值可能不存在的情况下使用可选值(optional), 可选值是: · 存在一个值,这个值等于 x 或 · 不存在任何值 注: 在 C 和 Objective ...

  8. SSH—Struts(三)—跑步者(Action)

    如已经描述Struts其基本原理和控制器ActionServlet,根据一个请求通过流ActionServlet之后就要到达Action类中做详细的处理了.ActionServlet通过ActionM ...

  9. Git学习笔记1--Git原理简单介绍

    Git是一个分布式的版本号控制工具,假设想用github等版本号控制系统,核心就是git,以下简介一些git的基础原理,原文:http://git-scm.com/book/en/Getting-St ...

  10. DevExpress asp.net 导出Excel 自动开启迅雷问题,默认保存为aspx页面

    目前采取曲线救国策略: 利用MVC ..... <dx:ASPxGridView ID="ASPxGridView1" runat="server" Au ...