一、     并行LINQ

  1. 1.  并行查询

.NET4在System.Linq名称空间中包含一个新类ParalleIEnumerable ,可以分解查询的工作使其分布在多个线程上。尽管Enmerable类给IEnunerable<T>接口定义了扩展方法,但

ParalleIEnumerable 类的大多数扩展方法是ParallelQuery<TSource>类的扩展。一个重要的例外是AsParallel()方法,它扩展了IEnumerable<TSource>接口,返回ParallelQuery<TSource>类,所以正常的集合类可以以平行方式查询。

例:

const int arraySize = 100000000;

var data = new int[arraySize];

var r = new Random();

for (int i = 0; i < arraySize; i++)

{

data[i] = r.Next(40);

}

现在可以使用LINQ查询筛选数据,获取筛选数据的总和。该查询用where子句定义了一个筛选器,仅会中对应值小于20的项,接着调用聚合函数Sum()方法 。与前面的LINQ查询的唯一区别是,这次调用了AsParallel()方法。

var sum = (from x in data.AsParallel()

where x < 20

select x).Sum();

与前面的LINQ查询一样,编译器会修改语法,以调用AsParallel()、Where()、Select()和Sum()方法。AsParallel()方法用ParallelEnumerable类定义,以扩展IEnumerable<T>接口,所以对简单的数据调用它。AsParallel()方法返回ParallelQuery<TSource>。因为返回的类型,所以编译器选择的Where()方法是ParallelEnumerable.Where(),而不是Enumerable.Where()。在下面的代码中Select()和Sum()方法也来自ParallelEnumerable类。与Enumerable类的实现代码相反,对于ParallelEnumerable类,查询是分区的,以便多个线程可以同时处理该查询。数组可以分为多个部分,其中每个部分由不同的线程处理,以筛选其余项。完成分区的工作后,就需要合并,获得所有部分的总和。

var sum=data.AsParallel().Where(x=>x<20).Select(x=>x).Sum();

运行这行代码就会启动任务管理器,这样就可以看出系统的所有CPU都在忙碌。如果删除AsParallel()方法,就不可能使用多个CPU。当然,如果系统上没有多个CPU,就不会看到并行版本带来改进。

  1. 2.  分区器

AsParallel()方法不仅扩展了IEnumerable<T>接口,还扩展了Partition类。通过它,可以影响要创建的分区。

Partitioner类用System.Collection.Concurrent命名空间定义,并且有不同变体。Create方法接受实现了IList<T>类的数组或对象。根据这一点,以及类型的参数loadBalance和该方法的一些重载版本,会返回一个不同的Partitioner类型。对于数组,.Net4包含派生自抽象基类OrderablePartitioner<TSource>的DynamicPartitionerForArray<TSource>类和StaticPartitionerForArray<TSource>类。

var q1 = (from x in Partitioner.Create(data).AsParallel()

where x < 20

select x).Sum();

也可以调用WithExecutionMode()和WithDegreeOfParallelism()方法可以传递ParallelExecutionMode的一个Default值或者ForceParallelism值。默认情况下,并行LINQ避免使用系统开销很高的并行机制。对于WithDegreeOfParallelism()方法,可以传递一个整数值,以指定并行运行的最大任务数。

例:

const int arraySize = 100000000;

var data = new int[arraySize];

var r = new Random();

for (int i = 0; i < arraySize; i++)

{

data[i] = r.Next(40);

}

Stopwatch watch = new Stopwatch();

watch.Start();

//一种写法,没有添加动态负载均衡,执行完所需要的时间1300毫秒

var q1 = (from x in Partitioner.Create(data).AsParallel()

where x < 80

select x).Sum();

//第二种写法,添加了动态负载均衡,执行完所需要的时间为660毫秒。

var q1 = (from x in Partitioner.Create(data,true).AsParallel()

where x < 80

select x).Sum();

watch.Stop();

Console.WriteLine(watch.ElapsedMilliseconds.ToString());

  1. 3.  取消

.Net提供了一种标准方式,来取消长时间运行的任务,这也适用于并行LINQ。要取消长时间的查询,可以给查询添加WithCancellation()方法,并传递一个CancellationToken令牌作为参数。CancellationToken令牌从CancellationTokenSource类中创建。该查询在单独的线程中运行,在该线程中,捕获一个OperationCancelException类型的异常。如果取消了查询,就触发这个异常。在主线程中,调用CancellationTokenSource类的Cancel()方法可以取消任务。

const int arraySize = 100000000;

var data = new int[arraySize];

var r = new Random();

for (int i = 0; i < arraySize; i++)

{

data[i] = r.Next(40);

}

var cts = new CancellationTokenSource();

new Thread(() =>

{

try

{

var sum = (from x in data.AsParallel().WithCancellation(cts.Token)

where x < 80

select x).Sum();

Console.WriteLine("query finished, sum: {0}", sum);

}

catch (OperationCanceledException ex)

{

Console.WriteLine(ex.Message);

}

}).Start();

Console.WriteLine("query started");

Console.Write("cancel? ");

int input = Console.Read();

if (input == 'Y' || input == 'y')

{

// cancel!

cts.Cancel();

}

Linq并行执行的更多相关文章

  1. 多线程之任务: Task 基础, 多任务并行执行, 并行运算(Parallel)

    Task - 基于线程池的任务(在 System.Threading.Tasks 命名空间下) 多 Task 的并行执行 Parallel - 并行计算(在 System.Threading.Task ...

  2. 重新想象 Windows 8 Store Apps (43) - 多线程之任务: Task 基础, 多任务并行执行, 并行运算(Parallel)

    [源码下载] 重新想象 Windows 8 Store Apps (43) - 多线程之任务: Task 基础, 多任务并行执行, 并行运算(Parallel) 作者:webabcd 介绍重新想象 W ...

  3. .net LINQ and PLINQ

    本文  学习自  微软官网文档   2016/12 LINQ 背景   以前写与DB 相关的代码, 程序员须要懂开发语言(C#, VB)和查询语言跟数据库交互. LINQ 的出现使应用程序形成基于集合 ...

  4. .Net多线程编程—Parallel LINQ、线程池

    Parallel LINQ 1 System.Linq.ParallelEnumerable 重要方法概览: 1)public static ParallelQuery<TSource> ...

  5. [C#]一个简易的、轻量级的方法并行执行线程辅助类

      一个简易的.轻量级的方法并行执行线程辅助类 在实际应用中,经常要让多个方法并行执行以节约运行时间,线程就是必不可少的了,而多线程的管理经常又是一件头疼的事情,比如方法并行执行异步的返回问题,方法并 ...

  6. 扩展、委托、Lambda、linq

    1.扩展 扩展是一个很有用的功能.如果你有一个类.不能修改,同时你又想给他加一个方法.这个过程就是扩展.扩展就是扩展方法. 例1: 类People public class People { publ ...

  7. PLINQ 并行操作Linq

    C#并行编程-PLINQ:声明式数据并行   目录 C#并行编程-相关概念 C#并行编程-Parallel C#并行编程-Task C#并行编程-并发集合 C#并行编程-线程同步原语 C#并行编程-P ...

  8. Linq表达式、Lambda表达式你更喜欢哪个?

    什么是Linq表达式?什么是Lambda表达式? 如图: 由此可见Linq表达式和Lambda表达式并没有什么可比性. 那与Lambda表达式相关的整条语句称作什么呢?在微软并没有给出官方的命名,在& ...

  9. Linq之旅:Linq入门详解(Linq to Objects)

    示例代码下载:Linq之旅:Linq入门详解(Linq to Objects) 本博文详细介绍 .NET 3.5 中引入的重要功能:Language Integrated Query(LINQ,语言集 ...

随机推荐

  1. Surprise团队第三周项目总结

    Surprise团队第二周项目总结 项目进展 这周我们小组的项目在上周的基础上进行了补充,主要注重在注册登录界面的实现,以及关于数据库的一些学习. 在设计注册登录界面时,每一块的地方控件都不一样,比如 ...

  2. Spring任务调度器之Task的使用

    Spring Task提供两种方式进行配置,正如大家所想吧,还是一种是annotation(标注),而另外一种就是XML配置了.但其实这里我觉得比较尴尬,因为任务调度这样的需求,通常改动都是比较多的, ...

  3. android aidl 进程间通信需要注意的地方(android.os.TransactionTooLargeException)

    转自:http://blog.sina.com.cn/s/blog_4e1e357d0102wau9.html 1.bus工程实现通过service实现aidl实体类 2.actor工程通过发起bin ...

  4. Android Sqlite数据库加密

    Android使用的是开源的SQLite数据库,数据库本身没有加密,加密思路通常有两个: 1. 对几个关键的字段使用加密算法,再存入数据库 2. 对整个数据库进行加密 SQLite数据库加密工具: 收 ...

  5. CentOS上yum安装JDK

    转: http://blog.csdn.net/onepiecehuiyu/article/details/17189571

  6. oracle单机改变归档路径

    oracle 归档日志文件路径设置 1.  查看LOG_ARCHIVE_DEST 与 ( LOG_ARCHIVE_DEST_n 或 DB_RECOVERY_FILE_DEST )参数情况注意(  LO ...

  7. Ajax - ASP.NET MVC 4 系列

           ASP.NET MVC 框架中包含一组 Ajax 辅助方法,可以用来创建表单和指向控制器操作的链接,它们是异步的,且不用编写任何脚本代码来实现程序的异步性,但需要引入脚本文件 jquer ...

  8. SQLSERVER系统视图,系统表,sys.sql_modules视图

    SQLServer中提供了相当丰富的系统视图,能够从宏观到微观,从静态到动态反应数据库对象的存储结果.系统性能.系统等待事件等等.同时 也保留了与早期版本兼容性的视图,主要差别在于SQLServer2 ...

  9. java-final关键字

    一.final理解 编程语言中关键字,final类不能被继承,因此final类的成员方法没有机会被覆盖,默认都是final的.在设计类时候,如果这个类不需要有子类,类的实现细节不允许改变,并且确信这个 ...

  10. Beta版本冲刺——day3

    No Bug 031402401鲍亮 031402402曹鑫杰 031402403常松 031402412林淋 031402418汪培侨 031402426许秋鑫 站立式会议 大将回归,基本功能接口也 ...