gpt4 book ai didi

c# - 并行聚合不捕获所有迭代

转载 作者:行者123 更新时间:2023-11-30 17:01:21 24 4
gpt4 key购买 nike

我的代码使用简单的 For 循环效果很好,但我想加快速度。我正在尝试调整代码以使用多个内核并使用 Parallel For。

在高层次上,我从 CalcRoutine 收集数千个帐户的结果,并将结果存储在一个包含 6 个元素的数组中。然后我重新运行这个过程 1,000 次。每个 6 元素数组中元素的顺序很重要,但是这 6 个元素数组的最后 1,000 次迭代的顺序并不重要。当我使用 For 循环运行代码时,我得到了一个包含 6,000 个元素的长列表。但是,当我尝试使用 Parallel For 版本时,我得到了接近 600 的结果。我已经确认“return localResults”行被调用了 1,000 次,但由于某种原因,并非所有 6 个元素数组都被添加到列表 TotalResults .任何关于为什么这不起作用的见解将不胜感激。

object locker = new object();

Parallel.For(0, iScenarios, () => new double[6], (int k, ParallelLoopState state, double[] localResults) =>
{
List<double> CalcResults = new List<double>();
for (int n = iStart; n < iEnd; n++)
{
CalcResults.AddRange(CalcRoutine(n, k));
}
localResults = this.SumOfResults(CalcResults);
return localResults;
},
(double[] localResults) =>
{
lock (locker)
{
TotalResults.AddRange(localResults);
}
});

编辑:这是“非并行”版本:

for (int k = 0; k < iScenarios; k++)            
{
CalcResults.Clear();
for (int n = iStart; n < iEnd; n++)
{
CalcResults.AddRange(CalcRoutine(n, k));
}
TotalResults.AddRange(SumOfResults(CalcResults));
}

1 个场景的输出是 6 个 double 的列表,2 个场景的输出是 12 个 double 的列表,... n 个场景 6n 个 double 。

还有一个问题,我检查了“TotalResults.AddRange...”被调用的次数,它不是完整的 1,000 次。为什么不每次都调用它?有了锁,每个线程不应该等待这个部分变得可用吗?

最佳答案

查看 Parallel.For 的文档

These initial states are passed to the first body invocations on each task. Then, every subsequent body invocation returns a possibly modified state value that is passed to the next body invocation. Finally, the last body invocation on each task returns a state value that is passed to the localFinally delegate

但是您的body 委托(delegate)忽略了localResultsincoming 值|此任务中的前一次迭代返回的。将循环状态设为数组使得编写正确的版本变得棘手。这会起作用但看起来很乱:

//EDIT - Create an array of length 0 here    V    for input to first iteration
Parallel.For(0, iScenarios, () => new double[0],
(int k, ParallelLoopState state, double[] localResults) =>
{
List<double> CalcResults = new List<double>();
for (int n = iStart; n < iEnd; n++)
{
CalcResults.AddRange(CalcRoutine(n, k));
}
localResults = localResults.Concat(
this.SumOfResults(CalcResults)
).ToArray();
return localResults;
},
(double[] localResults) =>
{
lock (locker)
{
TotalResults.AddRange(localResults);
}
});

(假设 Linq 的可枚举扩展在范围内,对于 Concat )

我建议使用不同的数据结构(例如 List<double> 而不是 double[] )用于更自然地允许向其添加更多元素的状态 - 但这将意味着更改 SumOfResults你还没有显示。或者只是让它更抽象一点:

Parallel.For(0, iScenarios, Enumerable.Empty<double>(),
(int k, ParallelLoopState state, IEnumerable<double> localResults) =>
{
List<double> CalcResults = new List<double>();
for (int n = iStart; n < iEnd; n++)
{
CalcResults.AddRange(CalcRoutine(n, k));
}
return localResults.Concat(this.SumOfResults(CalcResults));
},
(IEnumerable<double> localResults) =>
{
lock (locker)
{
TotalResults.AddRange(localResults);
}
});

(如果它按照您假设的方式工作,他们为什么要您提供两个单独的委托(delegate),如果它所做的只是在从 body 返回时立即调用 localFinally 返回值?)

关于c# - 并行聚合不捕获所有迭代,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21151025/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com