When to use TaskCreationOptions.LongRunning?

bas picture bas · Jun 3, 2016 · Viewed 20.7k times · Source

I've wondered this for quite a while, but never really found the answer.

I understand that it's a hint for the task scheduler where the task will run on, and that the task scheduler can (or nowadays will?) decide to instantiate a non-thread-pool thread for that task.

What I don't know (and surprisingly can't find nowhere on the internet) is some "rule of thumb" when to specify a task as long-running. Is one second long? 30 seconds? A minute? 5 minutes? Does it have a relation with the amount of tasks the application uses? Should I as programmer do some calculation with the #threads in the thread pool, how many Tasks I create, how many will be long-running at the same time, and based on that make a decision whether to use a long running task?

Hope to learn something here.

Answer

Hans Passant picture Hans Passant · Jun 3, 2016

It can be quantified, the threadpool manager adds an extra thread beyond the optimum when the existing tp threads don't complete soon enough. It does this twice a second, up to the maximum set by SetMaxThreads(). Which has a very high default value. The optimum is the number of processor cores the machine has available, 4 is typical. Running more threads than available cores can be detrimental due to the context switching overhead.

It does this based on the assumption that these existing threads don't make progress because they are not executing enough code. In other words, they block on I/O or a lock too much. Such threads therefore don't use the cores efficiently enough and allowing an extra thread to execute is entirely appropriate to drive up processor usage and get more work done.

So it is "long running" when the thread takes more than half a second. Keep in mind that this is a very long time, it equals roughly 4 billion processor instructions on a modern desktop class machine. Unless you are running computationally heavy code like calculating the value of pi to a gazillion digits, thus actually executing those 4 billion instructions, a practical thread can only take this long when it does block too often. Which is very common, something like a dbase query is often slow and executed on a worker thread and consumes little cpu.

It is otherwise up to you to verify that the assumption that the threadpool manager will make is accurate. The task should take a long time because it isn't using the processor efficiently. Task Manager is a simple way to see what the processor cores are doing in your program, albeit that it won't tell you exactly what code they are executing. You'll need a unit test to see the thread executing in isolation. The ultimate and only completely accurate way to tell you that using LongRunning was an appropriate choice is to verify that your app indeed gets more work done.