C# 并行聚合集合

C# 并行聚合集合,c#,parallel-processing,aggregate,parallel.foreach,C#,Parallel Processing,Aggregate,Parallel.foreach,我看过一些基本类型的并行聚合代码,例如 Parallel.For<int>(0, result.Count, () => 0, (i, loop, subtotal) => { subtotal += result[i]; return subtotal; }, (x) => Interlocked.Add(ref sum, x) ); Parallel.For(0,result.Count,()=>0,(i

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

Parallel.For<int>(0, result.Count, () => 0, (i, loop, subtotal) =>
    {
        subtotal += result[i];
        return subtotal;
    },
    (x) => Interlocked.Add(ref sum, x)
);
Parallel.For(0,result.Count,()=>0,(i,循环,小计)=>
{
小计+=结果[i];
返回小计;
},
(x) =>联锁。添加(参考和,x)
);
我想知道列表/其他集合是否有等效项,例如:

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

    subList.add(GetResultFor(currentID));
    return subList;
},
(x) =>
{
    lock(AllResults)
        AllResults.AddRange(subList);
};
列出所有结果;
Parallel.ForEach(allIDs,(currentID)=>
{
add(GetResultFor(currentID));
返回子列表;
},
(x) =>
{
锁定(所有结果)
AllResults.AddRange(子列表);
};
我猜没有什么比这更好、更整洁的了,但我想不出另外一种方法,当然不是通过标准的parralel.ForEach,因为我想不出你会怎么说“这个核心有这个范围,这个核心有这个范围”…

List AllResults=new List();
Parallel.ForEach(allid,()=>newlist(),(id,loopState,subList)=>
{
Add(GetResultFor(id));
返回子列表;
},
子列表=>
{ 
锁定(所有结果)
AllResults.AddRange(子列表);
});
我认为在这两个示例中,都可以更好地为您服务,并且在使用非线程安全集合时无需手动锁定

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

var sum = result.AsParallel().Sum();
List<Result> results = allIDs.AsParallel()
                             .Select(id => GetResultFor(id))
                             .ToList();
您使用
列表的第二个示例可以转换为:

var sum = result.AsParallel().Sum();
List<Result> results = allIDs.AsParallel()
                             .Select(id => GetResultFor(id))
                             .ToList();
List results=allIDs.AsParallel()
.选择(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)总是可以并行进行…REDUCT(Sum)太“排序”…您可以使用多个工作线程对所有不同的和进行求和,直到剩下“最后一个”和。通常(90%)同步求和所有内容会得到最佳结果


另一个选择多的示例:

        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();
IList manyNumbers=new List();
对于(int i=0;i<16;i+=2)
{
manyNumbers.Add(可枚举)范围(2
{
IEnumerable somePrimes=sumNums.Where(num=>
{

对于(long i=2;i),第一个代码块几乎肯定比根本不使用并行程序慢。为什么这么说?也许我没有展示一个合理的psudo代码。我把它想象成每个线程都有自己的“范围”要处理,并不是每个人都返回一个1的列表。这几乎总是一个可怕的想法。在性能方面,甚至更糟糕的是,在调试竞争条件方面。有人能解释为什么吗?代价高昂的部分在“getresultfor”中它们可以独立运行,所以我想在Parralel中运行它们,但我需要最终结果都存储在同一个列表中。那么应该怎么做呢?@aku这是针对第一个代码块吗?很抱歉,我想你误解了我的帖子。我不想要Parralel,因为这会导致一个总数,我只是把它作为一个示例发布这是我以前见过的例子。但我非常感谢你提醒我,这个块实际上不是很好。我的主要问题是如何做更复杂的函数,并将结果添加到可枚举的“may”中。这完全取决于
ToList
Sum
的工作方式……一般来说,调用
ToList
意味着您要等到表达式在那里完成求值,然后再调用。忽略它意味着PLINQ可以决定同时进行求值和求和……这在更复杂的场景中可能非常重要s、 ..@AK_u查询的具体化将为您提供与您使用不同执行并随后对其进行迭代时相同的性能。您可能会看到,如果集合足够大,您的系统消耗的内存将比延迟执行时更多。查询本身的性能将基于底层源代码,以及
GetResultFor
实际需要多长时间,因为我们只在这里投影元素,其他什么都没有。@AK_u这与傲慢无关。这只是我在试图理解为什么你告诉人们调用
ToList
可能会进一步降低性能,这是一个模棱两可的注释,无法说明问题你思路背后的故事。
ToList
唯一能做的就是具体化查询。这可能是OP想要的行为,也可能不是OP想要的行为,但你不知道,因为我们不知道OP打算用这些代码做什么。所以像你这样说一些笼统的话可能会导致人们错误地思考操作。Th谢谢你,我已经用这种方法处理了一半的时间。使用“tolist”和不使用“tolist”没有区别因为我对结果查询所做的唯一一件事就是循环查询。我目前正在尝试看看是否可以进一步加快查询速度。@chrispepper1989太棒了!很高兴它能帮上忙:)@Matias_Cicero,谢谢你,这肯定是最接近我要求的答案,但是你会说这可能比我标记为最佳答案的更快或更慢吗?我标记了这一个,因为它允许我在最短的时间内实现我需要的way@chrispepper1989这甚至比不上经典的同步和顺序事实上,我不会在我的项目中使用这段代码,我可能会按照@Yuval的建议使用PLinq。我写这篇文章是因为它回答了关于如何在
并行中实现同步的明确问题。ForEach
非常好,我觉得非常感谢你和Yuval:)@Matiascero如果不知道
GetResultFor()
的作用以及需要多长时间,你怎么能说这不比同步方式快呢?