gpt4 book ai didi

c# - Parallel.ForEach 在迭代结束时变慢

转载 作者:太空宇宙 更新时间:2023-11-03 15:14:15 25 4
gpt4 key购买 nike

我有以下问题:

我正在使用 parallel.foreach 迭代来处理相当 CPU 密集型的工作负载(对许多项目应用一种方法)并且它对大约前 80% 的项目工作正常 - 使用所有 cpu 内核非常好。

随着迭代似乎接近尾声(我会说大约 80%),我看到线程数量开始逐个核心下降,最后,最后大约 5% 的项目被处理只有两个核心。因此,为了使用所有内核直到最后,它在迭代结束时会非常缓慢地减速。

请注意,每个项目的工作量可能大不相同。一个可以持续 1-2 秒,另一个可能需要 2-3 分钟才能完成。

非常欢迎任何想法,建议。

使用的代码:

var source = myList.ToArray();
var rangePartitioner = Partitioner.Create(0, source.Lenght);
using (SqlConnection connection =new SqlConnection(cnStr))
{
connection.Open();
try
(
Parallel.ForEach(rangePartitioner, (range, loopState) =>
{
for(int i = range.Item1; i<range.Item2; i++)
{
CPUIntensiveMethod(source[i]);
}
});
}
catch(AggretateException ae)
{ //Exception cachting}
}

最佳答案

这是并行度每次计算这一事实不可避免的结果。很明显,整个并行批处理的运行速度不能比工作集中最慢的单个项目所用的时间快。


想象一下有 100 个项目的批处理,其中 8 个是慢速的(假设运行 1000 秒),其余的是快速的(假设运行 1 秒)。您可以在 8 个线程中以随机顺序启动它们。很明显,最终每个线程都会计算您长期运行的项目之一,此时您会看到充分利用。最终,首先击中他们的长操作的人将完成他们的长操作并迅速完成所有剩余的短操作。那时你只有一些长操作等待完成,所以你会看到事件利用率下降..即在某个时候只剩下 3 个操作要完成,所以只有 3 个核心在使用中。


缓解策略

  • 您的长时间运行的项目可能适合“内部并行”,从而使它们具有更快的最小运行时间限制。
  • 您的长时间运行的项目可能能够被识别并优先启动(这将确保您尽可能长时间地充分利用 CPU)
  • (请参阅下面的更新)在主体可以长时间运行的情况下不要使用分区,因为这只会增加此效果的“命中率”。 (即完全摆脱你的 rangePartitioner )。这将大大减少这种效果对您的特定循环的影响

无论哪种方式,您的批处理运行时间都受批处理中最慢项目的运行时间限制。


更新 我还注意到您在循环中使用了分区,这大大增加了这种效果的范围,即您说的是“将这个工作集分解为 N 个工作集”并且然后并行运行这 N 个工作集。在上面的示例中,这可能意味着您将(比方说)3 个长操作放入同一个工作集中,因此它们将在同一个线程上处理。因此,如果内部主体可以长时间运行,您应该使用分区。例如这里关于分区的文档 https://msdn.microsoft.com/en-us/library/dd560853(v=vs.110).aspx都说这是针对矮个子的

关于c# - Parallel.ForEach 在迭代结束时变慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39698900/

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