并行任务的执行顺序控制

3

我有一个表名列表(student、exam、school)。

我使用Parallel.ForEach循环迭代表名,并对每个表进行处理,MaxDegreeOfParallelism = 8

我的问题是,我的Parallel.ForEach并不总是进行工作窃取。例如,当剩下两个表需要处理时,它们可能会一个接一个地处理,而不是并行进行处理。我试图提高性能和增加吞吐量。

我尝试通过创建自定义TaskScheduler来实现这一点,但是,对于我的实现,我需要按照最简单的任务顺序排列任务列表,以便它们不会被运行时间较长的表卡住。但我不能通过对传递给Parallel.ForEach的列表 List< string > 进行排序来实现这一点,因为任务是由 TaskScheduler 无序入队的。因此,我需要一种方法,在我的CustomTaskScheduler中对任务列表进行排序,该任务调度程序基于https://psycodedeveloper.wordpress.com/2013/06/28/a-custom-taskscheduler-in-c/

如何控制Parallel.ForEach传递任务的顺序使其按顺序入队到TaskScheduler中?


为什么不使用任务列表和WaitAll呢? - Sandris B
@SandrisB 我不熟悉,但是快速谷歌告诉我它是用于异步编程的 - 我需要让任务并行执行,使用WaitAll如何实现? - TurgidWizard
在这里展示您的代码将是理想的。 - Enigmativity
2个回答

3
Parallel.ForEach 方法根据源类型使用两种不同的分区策略。如果源是一个数组或者 List,则进行静态(预先)分区。如果源是一个真正的 IEnumerable,则进行动态(即时)分区。动态分区具有理想的抢占式工作行为,但开销较大。在您的情况下,开销并不重要,因为您的工作负载非常低。
为确保分区是动态的,最简单的方法是使用Partitioner.Create 方法包装您的源:
string[] tableNames;
Parallel.ForEach(Partitioner.Create(tableNames), tableName =>
{
    // Process table
});

¹(该表达式源自源代码的评论)


1
非常感谢,这非常有见地和有帮助,初步检查看起来像魔法一样有效! - TurgidWizard

1
我建议查找partitioners。在并行循环中管理线程会带来一些开销,因此有一些内置逻辑可以尝试在保持工作负载平衡的同时保持这种开销较小。这是通过将列表分成块并调整块大小以达到某个甜点来实现的。
如果平衡是目标,我猜按最小的任务排序会反对分区器的平衡。如果平衡是目标,我会尝试按最大的任务排序。另一件事是使用一些常量块大小对工作项进行分区,看看是否有帮助。或者甚至编写自己的分区器。
我不确定强制执行一些执行顺序是否是一个好主意。由于您无法控制操作系统调度程序,因此不能有任何保证的顺序。即使您可以使其更加有序,也可能会牺牲吞吐量。
此外,如果您花费大量时间优化并行化,您是否确定代码的其余部分已经优化了?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接