Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parallel.ForEach doesn't make use of all available thread pool threads

Why when I run the following example do I only have the Parallel.ForEach run the number of threads equal to the number of cores on my machine? I thought Parallel.ForEach gives you thread pool threads of which there are approx 1000?

            int threads1;
            int threads2;

            ThreadPool.GetAvailableThreads(out threads1,out threads2);
            var list = Enumerable.Range(1, 200);
            var po = new ParallelOptions
            {
                MaxDegreeOfParallelism = 100
            };

            Parallel.ForEach(list, po, x =>
                {
                    Console.WriteLine("Thread:" + Thread.CurrentThread.ManagedThreadId);
                    Thread.Sleep(1000);
                });

Am I missing something here?

like image 906
user183872 Avatar asked Oct 02 '15 18:10

user183872


2 Answers

Parallel.ForEach uses managed thread pool to schedule parallel actions. The number of threads is set by ThreadPool.SetMinThreads and ThreadPool.SetMaxThreads. By default, the minimum number of threads is set to the number of processors on a system.

To minimize the usage of system resources, the number of pool threads is kept as low as possible. When all the pool threads are busy executing actions, the scheduler gradually spawns new threads.

The value MaxDegreeOfParallelism is usually used to prevent Parallel.For from scheduling more than the specified number of tasks simultaneously. It is useful in case of long computations when there is no sense of using more threads than the number of cores.

If you modify the code by increasing the sleep time Thread.Sleep(100000);, you will see the creation of new threads.

If you call ThreadPool.SetMinThreads(100, 100); before Parallel.ForEach, you will see all 100 actions started simultaneously.

like image 195
Andrey Nasonov Avatar answered Oct 18 '22 21:10

Andrey Nasonov


You will get the best performance if the number of threads doesn't exceed the number of processing cores.

Each core can only process one thread at a time. If there are more threads than cores, the OS has to switch between threads. Context switching is an expensive operation, you should try to avoid it in multi-threaded applications.

If the operations you perform are IO-bound, you should use Tasks instead of Paraller.For. It's nicely explained on Scott Hanselman's blog.

The details of Parallel.For thread management are explained in details in Andrey Nasonov's answer, so I will not repeat it.

If you want to learn more about threading, TPL and asynchrounous I/O I recommend CLR via C# book

like image 37
Jakub Lortz Avatar answered Oct 18 '22 22:10

Jakub Lortz