Pro LINQ 之六:并行LINQ查询

写在前面

《Pro LINQ in C# 2010》第22章开始,讲的是Parallel LINQ,即并行LINQ查询,简称PLINQ。这本是LINQ的一个重大改进和提升,但该书却在这一重大主题上草草结束。作为入门,我更喜欢MSDN上的一篇文章:在多核处理器上运行查询

PLINQ概要

PLINQ属于LINQ to Objects,将IEnumerable<T>类型的序列用AsParallel()运算符转换为ParallelQuery<T>,即可自动激活并行LINQ查询。

PLINQ的核心在于分页——将待查询的序列按CPU核心数量分为若干页,交给各CPU进行运算。

若没有定序运算符AsOrdered(),则PLINQ返回的查询结果是乱序的、不可靠的(Unstable),多数情况下是按分页顺序取出查询结果。但使用AsOrdered()也是有代价的,因为要重新排序,因此可能抵消使用PLINQ的收益。

多数情况下,PLINQ会自主决定是否采用并行计算。使用WithExecutionMode(ParallelExecutionMode.ForceParallelism)方法,可以强制使用并行查询。

使用WithDegreeOfParallelism(),可以限定并行的分页数,简单地可理解为交给几个CPU核心计算。

PLINQ中的异常处理

区别于通常的串行查询在遇到异常后停止查询,PLINQ中的每个分支是独立的,某个分支发生异常,只会导致该分支的查询被中断。

PLINQ会将每个并行分支中发生的异常收集并封装在异常System.AggregateException里,并在PLINQ查询得到实际执行时被抛出。因此我们要做的,就是利用try-catch捕获异常AggregateException。而在AggregateException内部,提供有一个方法Handle()用以依次处理从各分支中搜集到的异常。该方法的参数为一委托,可以用lambda表达式实现。该委托的返回类型为bool:如果异常被我们处理了,则返回true;如果异常靠我们自己处理不了,就返回false。就象作者在示例中的如下处理方式:

IEnumerable<string> results = presidents
            .AsParallel()
            .Select(p =>
            {
                if (p == "Arthur" || p == "Harding")
                    throw new Exception(String.Format("Problem with President {0}", p));
                return p;
            });

try
{
    foreach (string president in results)
    {
        Console.WriteLine("Result: {0}", president);
    }
}
catch (AggregateException agex)
{
    agex.Handle(ex =>
    {
        Console.WriteLine(ex.Message);
        return true;
    });
}

通过在select选择子中的lambda表达式抛出异常,然后在try-catch块中捕获,再利用捕获到的AggregateException方法Handle()依次取出其中搜集到的异常。Handle()方法的参数有两个,一个是搜集到的异常,一个是Func<>(可以用Lambda表达式实现)。

PLINQ的其他操作

Range()

Repeat()

Empty()

与LINQ to Object的类似。

AsOrdered()

按源序列中的先后顺序返回查询结果

AsUnordered()

相当于Undo AsOrdered()

AsParallel()

转换成ParallelQuery<T>

AsSequential()

AsEnumerable()

作用与AsParallel()相反

WithDegreeOfParallelism(int degree)

设置分页数

WithExecutionMode(ParallelExecutionMode)

是否强制启动并行查询

Default:由PLINQ决定是否启动并行查询

ForceParallelism:强调启动并行查询

WithMergeOptions(ParallelMergeOptions)

返回查询结果的时机

NotBuffered:产生结果即刻返回

FullyBuffered:待全部结果产生后才返回

AutoBuffered/Default:由PLINQ决定Buff大小,并在Buff填满时返回结果

Cast()

OfType()

类似LINQ to Objects中的操作

ForAll()

类似泛型的ForEach()


(全书完)

原文地址:https://www.cnblogs.com/Abbey/p/2122820.html