20

I understand that the new TPL (Task Parallel Library) has implemented the Parallel.ForEach such that it works with "expressed parallelism." This means it does not guarantee that your delegates will run in multiple threads, but rather it checks to see if the host platform has multiple cores, and if true, only then does it distribute the work across the cores (essentially 1 thread per core).

If the host system does not have multiple cores (getting harder and harder to find such a computer) then it will run your code sequentially like a "regular" for each loop would. Pretty cool stuff, frankly.

Normally I would do something like the following to place my long-running operation on a background thread from the ThreadPool:

ThreadPool.QueueUserWorkItem(new WaitCallback(targetMethod), new Object2PassIn() );

In a situation whereby the host computer only has a single core does the TPL's Parallel.ForEach automatically places the invocation on a background thread? Or, should I manually invoke any TPL calls from a background thread so that if I am executing from a single core computer at least that logic will be off of the GUI's dispatching thread?

My concern is if I leave the TPL in charge of all this I want to ensure if it determines it's a single core box that it still marshals the code that's inside of the Parallel.ForEach loop onto a background thread like I would have done, to not block my GUI.

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
BonanzaDriver
  • 6,411
  • 5
  • 32
  • 35
  • 1
    Just a quick follow up on this: TPL Rocks! Can't get over just how much faster I'm able to make various apps with just a few small adjustments using TPL calls versus the "standard" fare. I'm watching processing times on various items cut by upwards of 80%. MS really knocked it out of the park on this one - great job guys. – BonanzaDriver Jan 06 '11 at 01:52

5 Answers5

20

Your assumptions are incorrect.
Parallel.For is, always, a blocking call.

Even if the computer has multiple cores, it will still wait for all of the threads to finish before returning.

If you don't want to freeze the UI, you will always need to explicitly call the ThreadPool.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
1

Through my experience with Parallel.ForEach and Parallel.For loops, I have noticed that the order can be out of order, something you might want to consider before you implement.

Such as a basic for loop will produce:

Product 1 Product 2 Product 3 Product 4

And the Parallel loop can produce, but not always:

Product 3 Product 1 Product 2 Product 4

Just keep that in mind lads.

TGarrett
  • 562
  • 4
  • 15
0

I think if you have exact requirements about instance/thread count, you need to do it yourself. I get the impression that the Parallel.ForEach type of calls are for declaratively getting cores involved. I don't know for certain, but I have a sneaky suspicion that it would be a bad choice for something that does blocking i/o (as an example).

Joel Clark
  • 549
  • 2
  • 14
  • From the documentation I have read so far it was originally conceived for "processor bound" problem sets. But, this isn't to rule out using it for IO. In fact, what got me to take a serious look at the TPL is the fact that I have an app that performs approximately 7,800 web queries ... I have a dual quad core processor box (3.0 GHz Xeons) that is running 24GB of RAM on Windows 7 Ultimate 64-bit edition ... and those take ~25 to 28 minutes to complete. There's some additional processing of the download HTML, but you get my point. I changed this to a TPL call and it took < 5 minutes. – BonanzaDriver Jan 05 '11 at 02:39
0

Good question. I would assume that it will still spawn a thread even there is only a single core.

I would have to run a test on a single core machine. Since I don't have one, I will use virtual machine and set the it environment CPU to 1 and see how many thread the the Parallel ForEach will spawn.

You may want to read the following:

Does Parallel limit the Number of Active Threads

Community
  • 1
  • 1
dsum
  • 1,433
  • 1
  • 14
  • 29
0

By default the Parallel.ForEach method invokes the body delegate on the current thread and on ThreadPool threads¹.

If you configure the MaxDegreeOfParallelism with the value Environment.ProcessorCount, it will use as worker threads the current thread and also Environment.ProcessorCount - 1 threads from the ThreadPool. On a single core machine the Environment.ProcessorCount is 1, so in this case only the current thread will be used.

If you don't configure the MaxDegreeOfParallelism, the default value of this setting is -1 which means unlimited parallelism. This practically means that the ThreadPool will become immediately saturated. When the ThreadPool is saturated, it starts popping new threads to accommodate the demand at a rate of around one new thread per second². Having a saturated ThreadPool is rarely desirable, if ever, so my recommendation is to configure the MaxDegreeOfParallelism every time you use the Parallel family of methods³.

¹ It is possible to control where the body is invoked by configuring the TaskScheduler option. Finding suitable TaskSchedulers for special needs (or coding your own) is not trivial. Also be aware that the MaximumConcurrencyLevel of the scheduler affects (limits) the maximum degree of parallelism (link).
² At least this is how it behaves on .NET 6, on my quad core machine.
³ With the exception of the new Parallel.ForEachAsync API, that has a default MaxDegreeOfParallelism equal to Environment.ProcessorCount.

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104