The documentation of the ParallelOptions.MaxDegreeOfParallelism
property states that:
The
MaxDegreeOfParallelism
property affects the number of concurrent operations run byParallel
method calls that are passed thisParallelOptions
instance. A positive property value limits the number of concurrent operations to the set value. If it is -1, there is no limit on the number of concurrently running operations.By default,
For
andForEach
will utilize however many threads the underlying scheduler provides, so changingMaxDegreeOfParallelism
from the default only limits how many concurrent tasks will be used.
I am trying to understand what "no limit" means in this context. Based on the above excerpt from the docs, my expectation was that a Parallel.Invoke
operation configured with MaxDegreeOfParallelism = -1
would start executing immediately in parallel all the supplied actions
. But this is not what happening. Here is an experiment with 12 actions:
int concurrency = 0;
Action action = new Action(() =>
{
var current = Interlocked.Increment(ref concurrency);
Console.WriteLine(@$"Started an action at {DateTime
.Now:HH:mm:ss.fff} on thread #{Thread
.CurrentThread.ManagedThreadId} with concurrency {current}");
Thread.Sleep(1000);
Interlocked.Decrement(ref concurrency);
});
Action[] actions = Enumerable.Repeat(action, 12).ToArray();
var options = new ParallelOptions() { MaxDegreeOfParallelism = -1 };
Parallel.Invoke(options, actions);
Output:
Started an action at 11:04:42.636 on thread #6 with concurrency 4
Started an action at 11:04:42.636 on thread #7 with concurrency 5
Started an action at 11:04:42.629 on thread #1 with concurrency 1
Started an action at 11:04:42.636 on thread #8 with concurrency 3
Started an action at 11:04:42.630 on thread #4 with concurrency 2
Started an action at 11:04:43.629 on thread #9 with concurrency 6
Started an action at 11:04:43.648 on thread #6 with concurrency 6
Started an action at 11:04:43.648 on thread #8 with concurrency 6
Started an action at 11:04:43.648 on thread #4 with concurrency 6
Started an action at 11:04:43.648 on thread #7 with concurrency 6
Started an action at 11:04:43.648 on thread #1 with concurrency 6
Started an action at 11:04:44.629 on thread #9 with concurrency 6
The result of this experiment does not match my expectations. Not all actions were invoked immediately. The maximum concurrency recorded is 6, and sometimes 7, but not 12. So the "no limit" does not mean what I think it means. My question is: what does the MaxDegreeOfParallelism = -1
configuration means exactly, with all four Parallel
methods (For
, ForEach
, ForEachAsync
and Invoke
)? I want to know in details what's the behavior of these methods, when configured this way. In case there are behavioral differences between .NET versions, I am interested about the current .NET version (.NET 6), which also introduced the new Parallel.ForEachAsync
API.
Secondary question: Is the MaxDegreeOfParallelism = -1
exactly the same with omitting the optional parallelOptions
argument in these methods?
Clarification: I am interested about the behavior of the Parallel
methods when configured with the default TaskScheduler
. I am not interested about any complications that might arise by using specialized or custom schedulers.