MaxDegreeOfParallelism = Environment.ProcessorCount slows down execution time on my CPU

15,962

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

By default, For and ForEach will utilize however many threads the underlying scheduler provides. Changing MaxDegreeOfParallelism from the default only limits how many concurrent tasks will be used.

This means that setting MaxDegreeOfParallelism to the number of processors will in fact limit the capacity of the Parallel.For loop to use the optimal amount of threads for the work load. For example, I have a migration job that uses close to 60 threads on around 600 iterations of long-running code, a lot more than the 1 thread per processor limit that you're trying to set.

MaxDegreeOfParallelism or ThreadPool.SetMaxThreads should only be used if you explicitly need to prevent more than a given number of threads from executing. For example, if using an Access database, I would set it to 64, because that's the maximum number of concurrent connections that can be handled by Access for a single process.

Share:
15,962
Harry Boy
Author by

Harry Boy

Updated on June 05, 2022

Comments

  • Harry Boy
    Harry Boy almost 2 years

    I have the following program (that I got from http://blogs.msdn.com/b/csharpfaq/archive/2010/06/01/parallel-programming-in-net-framework-4-getting-started.aspx) that splits a task up using Parallel.For loop

    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;
        }
    }
    

    When I run this test several times I get times of:

    1992, 2140, 1783, 1863 ms etc etc.

    My first question is, why are the times always different?? I am doing the exact same calculations each time yet the times vary each time.

    Now when I add in the following code to make use of all the available processors on my 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);
            });
    

    I notice that the execution times actually increase!! The times are now:

    2192, 3192, 2603, 2245 ms etc etc.

    Why does this cause the times to increase? Am I using this wrong?

  • Erik
    Erik over 10 years
    Good answer. As mentioned, it is best to not set this explicitly unless you have a specific reason to do so.
  • Harry Boy
    Harry Boy over 10 years
    I actually changed the value of MaxDegreeOfParallelism = ENvironment.ProcessorCount to MaxDegreeOfParallelism = 16 and saw that it ran faster. You see I'm trying to create a test tool that is used to test how long different CPUs perform a task and I want to have the same test for each CPu thats why I want to set a limit on the number of Threads.
  • Harry Boy
    Harry Boy over 10 years
    Can someone please explain to me the following. If I set MaxDegreeOfParallelism = Environment.ProcessorCount (Which is 8) does that mean one thread is running on each processor so that means the task is truely being executed in parallel? And if I set MaxDegreeOfParallelism to be 16 then that would mean that there are 2 threads running on each processor, but that each of these two threads have to switch between each other so it not true parallel processing??
  • Benjamin Beaulieu
    Benjamin Beaulieu over 10 years
    With TPL, you cannot assume by default that a specific number of threads will be created and executed simultaneously. It will create/run as many threads as needed for the work load. You could try to run it with ThreadPool.SetMinThreads as well as ThreadPool.SetMaxThreads set to 8, but I'm not even sure that would guarantee 8 threads. Also, you would need to consider the thread handling overload.
  • svick
    svick over 10 years
    I think it's important to differentiate between CPU-bound tasks and IO-bound tasks. Your long-running code is likely IO-bound, so it makes sense to use more than one thread per core. But the code in this question is CPU-bound, where it's usually best to use one thread per core.