【问题标题】:MaxDegreeOfParallelism = Environment.ProcessorCount slows down execution time on my CPUMaxDegreeOfParallelism = Environment.ProcessorCount 减慢 CPU 的执行时间
【发布时间】:2014-01-15 08:57:02
【问题描述】:

我有以下程序(我从 http://blogs.msdn.com/b/csharpfaq/archive/2010/06/01/parallel-programming-in-net-framework-4-getting-started.aspx 获得的)使用 Parallel.For 循环来拆分任务

class Program
{
    static void Main(string[] args)
    {
        var watch = Stopwatch.StartNew();


        Parallel.For(2, 20, (i) =>
        {
            var result = SumRootN(i);
            Console.WriteLine("root {0} : {1} ", i, result);
        });

        Console.WriteLine(watch.ElapsedMilliseconds);
        Console.ReadLine();
    }

    public static double SumRootN(int root)
    {
        double result = 0;
        for (int i = 1; i < 10000000; i++)
        {
            result += Math.Exp(Math.Log(i) / root);
        }
        return result;
    }
}

当我多次运行这个测试时,我得到的次数是:

1992、2140、1783、1863 毫秒等

我的第一个问题是,为什么时间总是不同的??我每次都在做完全相同的计算,但时间却每次都不同。

现在,当我添加以下代码以利用 CPU 上的所有可用处理器时:

        var parallelOptions = new ParallelOptions
        {
            MaxDegreeOfParallelism = Environment.ProcessorCount    (On my CPU this is 8)
        };

        Parallel.For(2, 20, parallelOptions, (i) =>
        {
            var result = SumRootN(i);
            Console.WriteLine("root {0} : {1} ", i, result);
        });

我注意到执行时间实际上增加了!!现在是:

2192、3192、2603、2245 毫秒等

为什么会导致次数增加?我用错了吗?

【问题讨论】:

  • 当您运行测试时,您的系统上还运行着什么?你是在 Release 模式下编译吗?是否附加了调试器?是否附加了探查器?
  • 要获得真正可比较的结果,请避免从这些线程输出到控制台。
  • 我打开了 Outlook、EverNote 和 Chrome 网络浏览器。
  • 它处于发布模式,没有附加任何调试器或任何东西。
  • 我认为这就是鸽子洞原理。您要求 8 个线程执行 18 个作业,最后 2 个作业花费的时间与 8 个作业一样多。当您取消限制时,TP 调度程序允许启动超过 个线程,因为它们需要太多时间。这会减慢每个工作,但可以摆脱最后两个。

标签: c# task-parallel-library parallel.foreach


【解决方案1】:

来自http://msdn.microsoft.com/en-us/library/system.threading.tasks.paralleloptions.maxdegreeofparallelism(v=vs.110).aspx

默认情况下,ForForEach 将使用底层调度程序提供的线程数。从默认值更改 MaxDegreeOfParallelism 只会限制将使用多少并发任务。

这意味着将MaxDegreeOfParallelism 设置为处理器数量实际上会限制Parallel.For 循环的容量,以使用最佳线程数来处理工作负载。例如,我有一个迁移作业,在大约 600 次长时间运行的代码迭代中使用了近 60 个线程,远远超过您尝试设置的每个处理器 1 个线程的限制。

MaxDegreeOfParallelismThreadPool.SetMaxThreads 仅应在您明确需要阻止超过给定数量的线程执行时使用。例如,如果使用 Access 数据库,我会将其设置为 64,因为这是 Access 可以为单个进程处理的最大并发连接数。

【讨论】:

  • 好答案。如前所述,除非您有特定的理由,否则最好不要明确设置。
  • 我实际上将 MaxDegreeOfParallelism = ENvironment.ProcessorCount 的值更改为 MaxDegreeOfParallelism = 16 并看到它运行得更快。你看我正在尝试创建一个测试工具,用于测试不同 CPU 执行任务的时间,我希望对每个 CPU 进行相同的测试,这就是为什么我要设置线程数限制。跨度>
  • 有人可以向我解释以下内容。如果我设置 MaxDegreeOfParallelism = Environment.ProcessorCount (即 8),这是否意味着每个处理器上都运行一个线程,这是否意味着该任务确实是并行执行的?如果我将 MaxDegreeOfParallelism 设置为 16,那么这意味着每个处理器上有 2 个线程在运行,但是这两个线程中的每一个都必须在彼此之间切换,所以它不是真正的并行处理??
  • 使用 TPL,您不能假设默认情况下会同时创建和执行特定数量的线程。它将根据工作负载的需要创建/运行尽可能多的线程。您可以尝试将ThreadPool.SetMinThreadsThreadPool.SetMaxThreads 设置为8 来运行它,但我什至不确定这是否能保证8 个线程。此外,您还需要考虑线程处理过载。
  • 我认为区分 CPU 密集型任务和 IO 密集型任务很重要。您的长时间运行的代码可能受 IO 限制,因此每个内核使用多个线程是有意义的。但是这个问题中的代码是受 CPU 限制的,通常最好每个内核使用一个线程。
猜你喜欢
  • 2016-10-24
  • 1970-01-01
  • 1970-01-01
  • 2023-03-29
  • 2011-11-20
  • 2017-11-02
  • 2012-12-31
  • 1970-01-01
  • 2022-01-23
相关资源
最近更新 更多