Ale*_*kiy 7 .net c# linq plinq task-parallel-library
所以主题是问题.
我得到那个方法AsParallel返回ParallelQuery<TSource>
使用相同LINQ关键字的包装器,System.Linq.ParallelEnumerable
而不是System.Linq.Enumerable
这很清楚,但是当我查看反编译源时,我不明白它是如何工作的.
让我们从最简单的扩展开始:Sum()方法.码:
[__DynamicallyInvokable]
public static int Sum(this ParallelQuery<int> source)
{
if (source == null)
throw new ArgumentNullException("source");
else
return new IntSumAggregationOperator((IEnumerable<int>) source).Aggregate();
}
Run Code Online (Sandbox Code Playgroud)
很明显,我们去找Aggregate()
方法吧.它是InternalAggregate方法的一个包装器,可以捕获一些异常.现在让我们来看看它.
protected override int InternalAggregate(ref Exception singularExceptionToThrow)
{
using (IEnumerator<int> enumerator = this.GetEnumerator(new ParallelMergeOptions?(ParallelMergeOptions.FullyBuffered), true))
{
int num = 0;
while (enumerator.MoveNext())
checked { num += enumerator.Current; }
return num;
}
}
Run Code Online (Sandbox Code Playgroud)
这是一个问题:它是如何工作的?我发现变量没有并发安全性,由许多线程修改,我们只看到迭代器和求和.这是魔术调查员吗?或者它是如何工作的?GetEnumerator()
返回QueryOpeningEnumerator<TOutput>
,但它的代码太复杂了.
最后,在我的第二次PLINQ 攻击中,我找到了答案。这很清楚。问题是枚举器并不简单。这是一个特别的multithreading
。那么它是如何运作的呢?答案是enumerator
不返回源的下一个值,它返回下一个分区的总和。因此,当实际求和工作在方法内部Environment.ProcessorCount
执行时,此代码仅执行 2,4,6,8... 次(基于) 。enumerator.MoveNext
enumerator.OpenQuery
因此,TPL 显然对源可枚举进行分区,然后对每个分区独立求和,然后执行此求和,请参阅IntSumAggregationOperatorEnumerator<TKey>
。这里没有魔法,只是可以潜得更深。