parallel.foreach个任务的控制执行顺序

Control order of execution of parallel.foreach tasks

我有一个 table 姓名列表(学生、考试、学校)。

我使用 Parallel.ForEach 循环遍历 table 名称并使用 MaxDegreeOfParallelism = 8 对每个 table 进行处理。

我的问题是我的 Parallel.ForEach 并不总是偷窃。例如,当有两个 table 待处理时,它们可能会一个接一个地处理,而不是并行处理。我正在尝试提高性能和增加吞吐量。

我尝试通过创建自定义 TaskScheduler 来做到这一点,但是,对于我的实施,我需要一个排序的任务列表,其中最简单的任务排在第一位,这样它们就不会被拖延更长时间-运行table秒。我似乎无法通过对传递给 Parallel.ForEach (List< string >) 的列表进行排序来做到这一点,因为任务被 TaskScheduler 乱序排队。因此,我需要一种方法来对 CustomTaskScheduler 中的任务列表进行排序,该列表基于 https://psycodedeveloper.wordpress.com/2013/06/28/a-custom-taskscheduler-in-c/

如何控制任务从 Parallel.ForEach 传递到 TaskScheduler 的顺序?

我建议查找 partitioners。在 Parallel 循环上管理线程会产生一些开销,因此有一些内置逻辑可以尽量减少这种开销,同时仍然适当地平衡所有内核之间的工作。这是通过将列表分成块并调整块大小以达到最佳效果来完成的。

我猜想将任务排序为最小的优先将不利于 paritioners 平衡。如果平衡是目标,我会尝试先订购最大的作品。我会尝试的另一件事是用一些恒定的块大小对工作项进行分区,看看是否有帮助。或者甚至编写您自己的分区程序。

我不确定尝试执行某些执行顺序是不是个好主意。由于您不控制 OS 调度程序,因此无法保证顺序。即使你可以让它更有序,也可能会以吞吐量为代价。

此外,如果您花费大量时间优化并行化,您确定其余代码已优化吗?

Parallel.ForEach 方法根据源的类型采用两种不同的分区策略。如果源是数组或 List,则它是静态分区的(预先)。如果源是 诚实至善¹ IEnumerable,它是动态分区的(在移动中)。动态分区具有工作窃取的理想行为,但开销更大。在您的情况下,开销并不重要,因为您的工作负载的粒度非常低。

要确保分区是动态的,最简单的方法是使用 Partitioner.Create 方法包装您的源:

string[] tableNames;
Parallel.ForEach(Partitioner.Create(tableNames), tableName =>
{
    // Process table
});

¹(该表达式是从source code中的评论中借用的)