Under which circumstances should I use different .NET threading methods?
.net, multithreading
Solution
Your basic understanding of `Thread`s and `ThreadPool` usage is more or less correct. `Task`, however, is a little more complicated.
Thread, ThreadPool, Task
First of all, a `Task` simply represents an asynchronous operation. It can execute on a `ThreadPool` thread (and if you're the one scheduling the task, then usually it does as you'll be using `TaskScheduler.Default` most of the time). It can also execute on a separate, non-thread-pool thread (when you specify `TaskCreationOptions.LongRunning`). It can even execute without a thread (think async IO operations: http://blog.stephencleary.com/2013/11/there-is-no-thread.html). Finally, when a `Task` encapsulates multiple async operations, it can be a combination of any of the above.
Ultimately `Task` adds a layer of abstraction over `Thread` and `ThreadPool` (which it uses internally when appropriate, and you have some degree of control over that when you're scheduling your tasks). Of the three threading methods `Task` should likely be your weapon of choice due to the language support built around it. Composing sequences of async operations using `Task` is a breeze compared to doing the same using low-level threading tools.
This does not, however, mean that `Thread` and `ThreadPool` are truly obsolete - merely that they shouldn't be your first point of call for new development. Setting aside the fact that they're still used by the framework under the covers even when you use `Task`, think of the amount of fully functional production code which makes use of `Thread` or `ThreadPool`, and what would happen to it once either of these types is marked with the `ObsoleteAttribute`. It will be a mess.
There are of course other reasons to use them too, i.e. extremely performance-sensitive scenarios (I'm sure there's more, but that's all I can think of right now).
Scheduling work with Task
Your considerations as to when to use `ThreadPool` or a new `Thread` still apply when you're scheduling a new `Task.` The guidelines here are simple:
- If the task is expected to be running continuously (tasks which run the entire time your process runs would be a good example) it is a good idea to specify the `TaskCreationOptions.LongRunning` flag when you start it. This is similar to starting a new thread.
- If you have some finite CPU-bound work which you want to perform asynchronously, push it out to the `ThreadPool` via `Task.Run` (it uses the default task scheduler, which happens to be the `ThreadPoolTaskScheduler` in the current implementation). This is similar to using `ThreadPool.QueueUserWorkItem(WaitCallback)`.
- If your task spends most of its lifetime performing asynchronous IO, you don't really need to worry about where it is executed.
Parallel
Now let's talk about the `Parallel` class and its members. First of all, you have `Parallel.Invoke`, which is roughly equivalent to starting a bunch of tasks in parallel and then blocking on their completion. This is only really useful when you're dealing with multiple blocking operations which you'd like to run in parallel. If that's your case and you don't want to mess with multiple `Task` instances, use it.
`Parallel.For` and `Parallel.ForEach` are a slightly different beast and are primarily used to parallelise CPU-bound work over elements of a collection (it's not a good idea to use them for IO work due to the way their inbuilt "load balancing" works, ultimately spawning too many threads unless you limit the degree of parallelism). These methods are conceptually different to `Thread`, `ThreadPool` and `Task`, and are closer to PLINQ. Use them where you would normally use a `for` or `foreach` loop in scenarios where parallelising collection element processing results in a measurable performance boost.
Problem
I've been doing some research on the different ways to handle a multiple threaded .NET application. Its becoming a little confusing. new Thread -> When one a single additional thread is needed? ThreadPool -> When you require multiple threads. It is cheaper to use an existing thread and leave the optimization (number based on the work involved) up to the framework. Task -> When you want an additional thread, and you happen to using .net 4.0 or above. Is this the API for new Thread? Parallel.for -> When you have multiple tasks and want the framework to handle the optimization for distributing work about different tasks based on the number of CPU cores. On MSDN, it does not state that the new Thread method is obsolete??