MaxDegreeOfParallelism = 2 shows 3 threads

491 views Asked by At

When I run the following code:

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

static void Main()
{
    ParallelOptions options = new ParallelOptions();
    options.MaxDegreeOfParallelism = 2; // -1 is for unlimited. 1 is for sequential. 

    try
    {
        Parallel.For(
                0,
                9,
                options,
                (i) =>
        {
            var result = SumRootN(i);
            Console.WriteLine("Thread={0}, root {0} : {1} ",
                Thread.CurrentThread.ManagedThreadId, i, result);
        });
    }
    catch (AggregateException e)
    {
        Console.WriteLine(
            "Parallel.For has thrown the following (unexpected) exception:\n{0}", e);
    }
}

I see that the output is:

Screenshot

There are 3 thread Ids here, but I have specified that the MaxDegreeOFParallelism is only 2. So why is there 3 threads doing the work instead of 2?

2

There are 2 answers

0
fejesjoco On

Quote 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, so changing MaxDegreeOfParallelism from the default only limits how many concurrent tasks will be used.

Translation: only 2 threads will be running at any given moment, but more (or even less) than 2 may be used out of the thread pool. You can test this with another writeline at the start of the task, you'll see that no 3 threads will enter concurrently.

0
Theodor Zoulias On

The MaxDegreeOfParallelism defines the maximum concurrent invocations of the body delegate. It doesn't define the maximum number of individual threads that might be involved in the body invocations. All the Parallel APIs do their work by creating tasks and executing them on the specified TaskScheduler. The default TaskScheduler is the TaskScheduler.Default, which schedules the execution of the tasks on the ThreadPool. The ThreadPool executes the tasks on any of the threads that are currently available in the pool. So the behavior that you observe is dominated by the behavior of the ThreadPool, and the behavior of the ThreadPool is not documented in details.

As an experiment you could configure the Parallel.For with a custom TaskScheduler that executes each task on a dedicated thread, instead of the ThreadPool. You can find an implementation here. You would see an even greater variability on thread IDs than in your original experiment.