For the sake of completeness, I've searched and read other articles here, such as:
Parallel.ForEach not spinning up new threads
but they don't seem to address my case, so off we go:
I have a Parallel.ForEach of an array structure, like so:
Dim opts As New ParallelOptions
opts.MaxDegreeOfParallelism = intThreads
Parallel.ForEach(udtExecPlan, opts,
Sub(udtStep)
Dim strItem As String = udtStep.strItem
Basically, for each item, I do some nested loops and end up calling a function with those loop assignments as parameters.
The function executes a series of intense calculations (which takes up most of the function's processing time) and records the results on an MSSQL table, and if some conditions are met, the function returns True, else False. If the result is True, then I simply Return from the parallel function Sub(udtStep) and another item from the array should continue. If the result is False, I simply go through another interation of the deepest nested loop, and so on, working towards the completion of the other outer loops, etc. So, in a nutshell, all nested loops are inside the main Parallel.ForEach loop, like so:
Parallel.ForEach(udtExecPlan, opts,
Sub(udtStep)
Dim strItem As String = udtStep.strItem
If Backend.Exists(strItem) Then Return
For intA As Integer = 1 To 5
For intB As Integer = 1 To 50
Dim booResult As Boolean = DoCalcAndDBStuff(strItem, intA, intB)
If booResult = True Then Return
Next intB
Next intA
End Sub)
It is important to notice that udtExecPlan has about 585 elements. Each item takes from 1 minute to several hours to complete.
Now, here's the problem:
Whether I do this:
Dim opts As New ParallelOptions
opts.MaxDegreeOfParallelism = intThreads
Parallel.ForEach(udtExecPlan, opts,
where intThreads is the core count, or whatever number I assign to it (tried 5, 8, 62, 600), or whether I simply omit the whole the ParallelOptions declaration and opts from the Parallel.ForEach statement, I notice it will spin up as many threads I have specified upto the total amount of cores (including HT cores) in my system. That is all fine and well.
For example, on an HP DL580G7 server with 32 cores / 64 HT cores and 128GB RAM, I can see 5, 8, 62 or 64 (using the 600 option) threads busy on the Task Manager, which is what I'd expect.
However, as the items on the array are processed, the threads on Task Manager "die off" (go from around 75% utilization to 0%) and are never spun up again, until only 1 thread is working. For example, if I set intThreads to 62 (or unlimited if I omitted the whole ParallelOptions declaration and opts from the Parallel.ForEach statement), I can see on the db table that 62 (or 64) items have been processed, but from then on, it just falls back to 1 thread and 1 item at a time.
I was expecting that a new thread would be spun up as soon as an item was done, as there are some 585 items to go through. It is almost as if 62 or 64 items are done in parallel and then on only 1 item until completion, which renders the whole server practically idling thereafter.
What am I missing?
I have tried some other different processes with a main Parallel.For loop (no other outer loop present, just as in this example) and get the same behaviour.
Why? Any thoughts welcome.
I am using VS.NET 2015 with .NET Framework 4.6.1, W2K8R2 fully patched.
Thanks!