Copyright 2008-2009, Paul Jackson, all rights reserved
A few years ago a friend of mine bought himself a Range Rover – not the pansy-Discovery from Land Rover, but the all-out, pick a fight with a rhinoceros and win, Range Rover. When he showed it off to me, he also showed me the Range Rover Driver’s Manual. Now, there’s not anything special about most Driver’s Manuals for cars, but this one had an interesting section – a section that should have been titled:
“Things You Probably Shouldn’t Do, But If You Must, Here’s How”
Instructions on how to drive your shiny, new Range Rover through a boulder-strewn gully, across 60-degree slopes and stuff like that. You know, the kind of things that wind up on YouTube with viewers shaking their heads and muttering, “stupid people doing stupid things”.
And the really bad part is that knowing those things are possible and having the instructions right there makes it very tempting to search out a boulder-strewn gully.
Anyway, Task Manager in the .Net 4 Parallel Extensions should have a documentation section like that: the things you probably shouldn’t do, but here’s how. After the perils of parallel programming in general, this is probably the functionality that’s going to get more people into more trouble than any other, simply from the temptation of knowing it’s there.
TaskManager is the class that creates and manages the threads used by the Parallel Extension classes. I believe I saw in a blog post somewhere that it’s going to be renamed to TaskScheduler before the .Net 4 release. Its interface is extremely simple:
The only things of real interest are the three properties: Current, Default and Policy.
Current and Default get the TaskManager that created the current thread and the default TaskManager for the application respectively. Policy gets the TaskManagerPolicy that the TaskManager was created with. So, basically, you can create a TaskManager and get some values from it, so what can we actually do with one?
A TaskManager gets passed into methods like Parallel.For to control the number and priority of threads used to process the parallel tasks (Parallel.For is examined in detail here):
The TaskManagerPolicy that’s passed to the TaskManager constructor defines the options available:
IdealThreadsPerProcessor is probably the one that’s going to tempt people the most, so let’s see how much trouble we can get into with that one.
As with the original example, this takes between four- and five-seconds to complete; but working on the theory that more is better, what happens if we increase the number of threads per core? Since we’re on a four-core system, let’s try 25 threads per core – that will create 100 threads, one for each iteration of the loop:
This had a slightly negative effect on the overall performance. Why? Well, because even if we have 100-threads running, they still have to share time on four cores, so there’s going to be contention as the system tries to fairly allocate time on each core to twenty-five threads.
The next thing someone might want to change is the ThreadPriority. For this test, I started the Parallel Extensions Ray Tracer example in the background. This application uses some significant processing resources, so all cores are close to 100% utilization while it’s running and there’s a significant performance degradation in the test application:
By changing the ThreadPriority, we can effect the performance either positively or negatively:
But while setting the Highest thread priority brought some performance back to our application, it had a very negative impact on the RayTracer running in the background, dropping the framerate from 5.2 to 2.8 frames-per-second:
TaskManager (or TaskScheduler, if it’s renamed to that) exists, but its power shouldn’t be used arbitrarily, because the effects can be undesirable. There are times when you might have perfectly legitimate needs to modify these defaults, but if you’re going to take your application on a ride across that 60-degree slope, make sure you know what you’re doing and test thoroughly so you don’t wind up on YouTube with people laughing at you.