Search code examples
c#.netparallel-processingtask-parallel-libraryparallel.foreach

TPL parallelism degree heuristic


Parallel.ForEach works over ThreadPool and by default TPL set the number of threads so it achieves the most performance based on some internal rules. But does .NET take into account parallel or nested Parallel.Foreach calls? For example let assume .NET decided that for current environment 10 threads is the best choice and we have:

Parallel.ForEach(collection1, (o1) => {Parallel.ForEach(collection2, (o2) => {...}})

Will it produce 10*10 threads?


The article I've found now make me think that "internal rules" of thread scheduling are so advanced and dynamic, that it can rationally handle described cases.


Solution

  • It does not produce threads but tasks. The two loops will indirectly cooperate. This cooperation is not perfect and might lead to more tasks queued than necessary/optimal. Each loop keeps one replica queued to the scheduler. This allows for the scheduler to start more tasks than optimal.

    In any case this does not mean that 100 threads are competing for OS resources. The threadpool is made to deal with oversubscription. It tends to produce more threads than there are CPUs, though, to be able to deal with blocking.

    Try to avoid nested loops. Usually, it is best to have only one parallel loop at a time. You could, for example, do this:

    var items =
     from o1 in collection1
     from o2 in collection2
     select new { o1, o2 };
    
    Parallel.ForEach(items, ...);
    

    If your architecture requires nested loops you can have them.