并行编程之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. Arcgis sde 10.1您不能创建在安装后的空间库,提示User has privileges required to create database objects.

    Geodatabase在10.1版本号也有较大的改进和更新,在用户体验和性能上都有变化,在实际的工作中可能会碰到各种奇怪的问题(事实上都是有原因的,须要我们对其工作机制有所了解才干避免其发生):近期须 ...

  2. 产品 线上 保持 和 支持 服务 (Support and maintenance solutions)

    Maintenance and support are the key factors for the smooth functioning of ERP solutions. ERP mainten ...

  3. C# 线程知识--使用Task执行异步操作

    在C#4.0之前需要执行一个复杂的异步操作时,只能使用CLR线程池技术来执行一个任务.线程池执行异步任务时,不知道任务何时完成,以及任务的在任务完成后不能获取到返回值.但是在C#4.0中引人了一个的任 ...

  4. AES加密CBC模式兼容互通四种编程语言平台【PHP、Javascript、Java、C#】

    原文:AES加密CBC模式兼容互通四种编程语言平台[PHP.Javascript.Java.C#] 由于本人小菜,开始对AES加密并不了解,在网络上花了比较多时间查阅资料整理: 先简单从百度找来介绍: ...

  5. Lenovo E46A-Win 7_无线灯亮但无法启动(耽误3天以上您信吗.....)问题: wlan autoconfig 依赖服务或组无法启动

    Lenovo E46A-Win 7_无线灯亮但无法启动(耽误3天以上您信吗.....)问题: wlan autoconfig 依赖服务或组无法启动 提示: windows7 无线连接服务wlan au ...

  6. MVC 编程模型及其变种

    MVC 编程模型及其变种 MVC全称是Model View Controller, 这是一个模型(model)-查看(view)-调节器(controller)缩写,这是通过通用的编程模型非.MVC当 ...

  7. VC编程 快捷键增加的几种方式

    VB运行时菜单字母的下划线消失 vc 给菜单增加快捷键RT给Menu里面的 文件 帮助 查看 等功能键加上一个快捷方式.比如按Ctrl+F1 就弹出查看下面的子功能.------解决方案------- ...

  8. HDU 5037 FROG (贪婪)

    Problem Description Once upon a time, there is a little frog called Matt. One day, he came to a rive ...

  9. linux_创建用户_copy远程文件_解压缩_执行

    查看历史命令: history 创建用户: sudo useradd -m -s /bin/bash cph  [会自动创建cph文件夹,并将才cph文件夹权限和组设为cph] 创建用户密码: pas ...

  10. MBProgressHUD -[__NSCFString sizeWithAttributes:]: unrecognized selector问题解决了

    最近的工作需要project打包成一个静态库文件,然后给他人使用提供. 在project有提及第三方库MBProgressHUD.在打包出静态库文件后,写了个Demo,引用了当中的一段代码来显示MBP ...