我有一个IEnumerable动作,它们在执行时消耗的时间是排序的。现在我希望所有这些都能并行执行。有没有比这个更好的解决方案?
IEnumerable<WorkItem> workItemsOrderedByTime = myFactory.WorkItems.DecendentOrderedBy(t => t.ExecutionTime);
Parallel.ForEach(workItemsOrderedByTime, t => t.Execute(), Environment.ProcessorCount);
所以我的想法是首先根据他们需要完成的时间执行所有费用任务。
编辑:问题是,是否有更好的解决方案可以在最短的时间内完成所有工作。
答案 0 :(得分:6)
解决您的XY Problem
因为否则可能会发生10个任务中的9个已完成,最后一个任务在1个核心上执行,所有其他核心无效。
您需要做的是告诉Parallel.ForEach
一次只从源列表中获取一个项目。这样,当你完成最后一项时,你不会在一个核心的队列中拥有一堆缓慢的工作项。
可以使用Partitioner.Create
并传递EnumerablePartitionerOptions.NoBuffering
Parallel.ForEach(Partitioner.Create(workItems, EnumerablePartitionerOptions.NoBuffering),
new ParallelOptions{MaxDegreeOfParallelism = Environment.ProcessorCount},
t => t.Execute());
答案 1 :(得分:2)
Parallel.ForEach
DecendentOrderedBy
的电话没有做任何好事的原因。虽然它可能会做坏事:如果默认分区程序决定执行范围分区,将12 WorkItems
分为4组3个项目,按IEnumerable
中的顺序排序。然后,第一个核心还有很多工作要做,从而产生了你试图避免的问题。Parallel.ForEach
仅占用一个项目,那么您自然会获得一些负载平衡。在大多数情况下,这将正常工作IEnumerable
的最佳(大多数情况下)解决方案(如您所见)将为Striped Partitioning个桶数=内核数。 AFIK那里你没有在.NET中获得这种开箱即用的功能。但是,您可以提供自定义OrderablePartitioner,以这种方式对数据进行分区。我很遗憾地说:“没有免费的午餐”