是否可以在执行Parallel.ForEach期间更改parallelOptions.MaxDegreeOfParallelism

Joh*_*ert 18 c# parallel-processing multithreading task-parallel-library

我正在运行一个多线程循环:

protected ParallelOptions parallelOptions = new ParallelOptions();

parallelOptions.MaxDegreeOfParallelism = 2;
Parallel.ForEach(items, parallelOptions, item =>
{
// Loop code here
});
Run Code Online (Sandbox Code Playgroud)

我想在执行并行循环期间更改parallelOptions.MaxDegreeOfParallelism以减少或增加多个线程.

parallelOptions.MaxDegreeOfParallelism = 5;
Run Code Online (Sandbox Code Playgroud)

它似乎没有增加线程.有没有人有任何想法?

Ian*_*cer 6

即使尝试这样做的问题在于它是一个难题.首先,您如何可靠地观察CPU和磁盘利用率?不经常采样CPU将很难了解实际发生的情况,并且采样磁盘利用率更难.其次,您的任务的粒度是多少,以及您可以多快实际更改正在运行的数量.第三,随着时间的推移,事情会迅速变化,因此您需要对观察结果进行某种过滤.第四,理想的线程数将取决于代码实际运行的CPU.第五,如果你分配了太多的线程,你就会在它们之间挣扎而不是做有用的工作.

有关.NET中的线程池如何处理决定使用多少线程的复杂任务的讨论,请参见http://msdn.microsoft.com/en-us/magazine/ff960958.aspx.

您还可以使用反射器并查看TPL用于分配线程的代码并避免不必要的上下文切换 - 它很复杂,甚至不考虑磁盘访问!

您可以尝试在较低优先级的线程上执行任务(创建自己的TaskScheduler线程,优先级低于正常的线程实际上非常简单).这至少可以确保您可以在不影响系统其余部分的情况下运行100%的CPU.弄乱线程优先级本身就充满了问题,但如果这是一个纯粹的后台任务,它可以是直截了当的,也可能有所帮助.

通常情况下,磁盘利用率是其他应用程序遭受贪婪应用程序攻击的真正罪魁祸首.Windows可以轻松地在应用程序之间公平地分配CPU,但是当涉及相对较慢的磁盘访问时,这是另一回事.您可能需要简单地限制应用程序以使其不会经常访问磁盘,而不是尝试动态调整运行的线程数.这是你可以做的事情,而无需改变活跃的线程数.

您还可以看一下SetPriorityClass通知操作系统您的流程不如系统上运行的其他应用程序重要的方法,请参阅如何增加流程的I/O优先级?欲获得更多信息.但这假设你的整个过程不那么重要,而不仅仅是这一部分.


Jim*_*hel 3

我不希望在调用后可以更改并行度ForEach。据我了解,ForEach将确定它可以创建多少个线程,创建那么多分区,并创建在这些分区上操作的线程。它没有必要说:“哦,等等,他改变了我们的资源分配,让我重新分区数组并重新分配线程。”