Parallel.ForEach
默认选项 。当任务受cpu限制时,一切都将正常运行。如果您具有四核并且没有其他进程在运行,则Parallel.ForEach
使用所有四个处理器。如果您具有四核,并且计算机上的某些其他进程正在使用一个完整的cpu,则Parallel.ForEach
大约使用三个处理器。
但是,如果任务不受cpu限制,则Parallel.ForEach
继续启动任务,努力使所有cpu保持忙碌状态。但是,无论并行执行多少任务,总是有更多未使用的cpu功能,因此它会继续创建任务。
如何判断您的任务是否受cpu限制?希望只是通过检查。如果要分解素数,这是显而易见的。但是其他情况并不那么明显。判断任务是否受cpu限制的经验方法是限制最大并行度,ParallelOptions.MaximumDegreeOfParallelism
并观察程序的行为。如果您的任务是cpu密集型的,那么您应该在四核系统上看到这样的模式:
如果行为如此,则可以使用默认Parallel.ForEach
选项并获得良好的效果。线性的cpu利用率意味着良好的任务调度。
但是,如果我在Intel i7上运行示例应用程序,则无论我设置的最大并行度如何,我都会获得约20%的cpu利用率。为什么是这样?由于分配了太多内存,垃圾回收器阻塞了线程。应用程序是资源绑定的,资源是内存。
同样,对数据库服务器执行长时间运行查询的I / O绑定任务也永远无法有效利用本地计算机上可用的所有cpu资源。并且在这种情况下,任务计划程序无法“知道何时停止”开始新任务。
如果您的任务不受cpu限制,或者cpu利用率不能以最大并行度线性扩展,则应建议Parallel.ForEach
不要一次启动太多任务。最简单的方法是指定一个数字,该数字允许对重叠的I / O绑定任务进行某种并行处理,但又不能过多,以至于使本地计算机对资源的需求不堪重负,或者使任何远程服务器负担过多。反复试验才能获得最佳结果:
static void Main(string[] args)
{
Parallel.ForEach(CreateData(),
new ParallelOptions { MaxDegreeOfParallelism = 4 },
(data) =>
{
data[0] = 1;
});
}