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中的评论中借用的)
我有一个 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中的评论中借用的)