并行聚合集合

Parallel Aggregate Collection

我看过基本类型的并行聚合代码,例如

Parallel.For<int>(0, result.Count, () => 0, (i, loop, subtotal) =>
    {
        subtotal += result[i];
        return subtotal;
    },
    (x) => Interlocked.Add(ref sum, x)
);

我想知道是否有 list/other 集合的等价物,例如:

List<Result> AllResults;
Parallel.ForEach(allIDs, (currentID) =>
{

    subList.add(GetResultFor(currentID));
    return subList;
},
(x) =>
{
    lock(AllResults)
        AllResults.AddRange(subList);
};

我猜没有什么比这更漂亮和整洁的了,但我想不出另一种方法,当然不是通过标准 parralel.ForEach 因为我想不出你会怎么说 "this core have this range, this core this range"...

List<Result> AllResults = new List<Result>();

Parallel.ForEach(allIDs, () => new List<Result>(), (id, loopState, subList) =>
{
   subList.Add(GetResultFor(id));
   return subList;
},
subList => 
{ 
     lock(AllResults)
         AllResults.AddRange(subList); 
});

我认为在这两个示例中,PLINQ 可以更好地为您服务,并且在使用非线程安全集合时无需手动锁定。

您的求和计算可以转换为:

var sum = result.AsParallel().Sum();

你的第二个例子 List<T> 可以转换为:

List<Result> results = allIDs.AsParallel()
                             .Select(id => GetResultFor(id))
                             .ToList();

请注意并行性仅与测试所说的一样好。并行并不总是会加速您的代码,有时它甚至可能会降低顺序循环的性能。

    var nums = Enumerable.Range(0, 1000000000);
    var parallel = nums.AsParallel();
    var mapped = parallel.Select(x => (long) unchecked( x * x)); 
    var sum = mapped.Sum();

    Console.WriteLine(sum);

映射 (Select) 总是可以并行发生...reduce (Sum) 也是如此 "sort of"...您可以使用许多工作线程来对所有不同的总和对求和直到剩下 "last" 总和。通常 (90%) 对所有内容进行同步求和会得到最好的结果。


另一个 select 的例子:

        IList<IEnumerable<long>> manyNumbers = new List<IEnumerable<long>>();
        for (int i = 0; i < 16; i+=2)
        {
            manyNumbers.Add(Enumerable.Range(2 << i, 2 << (i + 1)).AsParallel().Select(a=> (long)a));
        }
        var parallel = manyNumbers.AsParallel();

        var allPrimes = parallel.SelectMany(sumNums =>
        {
            IEnumerable<long> somePrimes= sumNums.Where(num =>
           {
               for (long i = 2; i <= Math.Sqrt(num); i++)
               {
                   if (num % i == 0)
                   {
                       return false;
                   }
               }
               return true;
           }
            );
            return somePrimes;
        }

        );

        foreach (var number in allPrimes)
        {
            Console.WriteLine(number);
        }

        long sumOfPrimes = allPrimes.Sum();


        Console.WriteLine(sumOfPrimes);
        Console.ReadLine();

这不是一个很好的算法...