Maybe I did not understand it right ... all the Parallel class issue :(
But from what I am reading now, I understand that when I use the Parallel I actually mobilize all the threads that exists in the threadPool for some task/mission.
For example:
var arrayStrings = new string[1000];
Parallel.ForEach<string>(arrayStrings, someString =>
{
DoSomething(someString);
});
So the Parallel.ForEach in this case is mobilizing all the threads that exists in the threadPool for the 'DoSomething' task/mission.
But does the call Parallel.ForEach will create any new thread at all?
Its clear that there will be no 1000 new threads. But lets assume that there are 1000 new threads, some case that the threadPool release all the thread that it hold so, in this case ... the Parallel.ForEach will create any new thread?
Parallel.Foreach does not create new threads, nor does it "mobilize all the threads". It uses a limited number of threads from the threadpool and submits tasks to them for parallel execution. In the current implementation the default is to use one thread per core.
I think you have this the wrong way round. From PATTERNS OF PARALLEL PROGRAMMING you'll see that Parallel.ForEach is just really syntactic sugar.
The Parallel.ForEach is largely boiled down to something like this,
The ThreadPool takes care of the scheduling. There are some excellent articles around how the ThreadPool's scheduler behaves to some degree if you're interested, but that's nothing to do with TPL.
Parallel does not deal with threads at all - it schedules TASKS to the task framework. THat then has a scheduler and the default scheduler goes to the threadpool. This one will try to find a goo number of threads (better in 4.5 than 4.0) and the Threadpool may slowly spin up new threads.
But that is not a functoin of parallel.foreach ;)
It never will. As I said - it has 1000 foreach, then it queues 10.000 tasks, Point. THe Task factory scheduler will do what it is programmed to do ((you can replace it). Generally, default - yes, slowly new threads will spring up WITHIN REASON.
Short answer:
Parallel.ForEach()
does not “mobilize all the threads”. And any operation that schedules some work on theThreadPool
(whichParallel.ForEach()
does) can cause creation of new thread in the pool.Long answer: To understand this properly, you need to know how three levels of abstraction work:
Parallel.ForEach()
,TaskScheduler
andThreadPool
:Parallel.ForEach()
(andParallel.For()
) schedule their work on aTaskScheduler
. If you don't specify a scheduler explicitly, the current one will be used.Parallel.ForEach()
splits the work between severalTask
s. EachTask
will process a part of the input sequence, and when it's done, it will request another part if one is available, and so on.How many
Task
s willParallel.ForEach()
create? As many as theTaskScheduler
will let it run. The way this is done is that eachTask
first enqueues a copy of itself when it starts executing (unless doing so would violateMaxDegreeOfParallelism
, if you set it). This way, the actual concurrency level is up to theTaskScheduler
.Also, the first
Task
will actually execute on the current thread, if theTaskScheduler
supports it (this is done usingRunSynchronously()
).The default
TaskScheduler
simply enqueues eachTask
to theThreadPool
queue. (Actually, it's more complicated if you start aTask
from anotherTask
, but that's not relevant here.) OtherTaskScheduler
s can do completely different things and some of them (likeTaskScheduler.FromCurrentSynchronizationContext()
) are completely unsuitable for use withParallel.ForEach()
.The
ThreadPool
uses quite a complex algorithm to decide exactly how many threads should be running at any given time. But the most important thing here is that scheduling new work item can cause the creating of a new thread (although not necessarily immediately). And because withParallel.ForEach()
, there is always some item queued to be executed, it's completely up to the internal algorithm ofThreadPool
to decide the number of threads.Put together, it's pretty much impossible to decide how many threads will be used by a
Parallel.ForEach()
, because it depends on many variables. Both extremes are possible: that the loop will run completely synchronously on the current thread and that each item will be run on its own, newly created thread.But generally, is should be close to optimal efficiency and you probably don't have to worry about all those details.