431

There are two classes available in .NET: Task and Thread.

  • What is the difference between those classes?
  • When is it better to use Thread over Task (and vice-versa)?
starball
  • 20,030
  • 7
  • 43
  • 238
Jacek
  • 11,661
  • 23
  • 69
  • 123
  • 50
    Read [this](http://www.albahari.com/threading/). – MoonKnight Nov 17 '12 at 09:00
  • 24
    Prefer Task unless you need thread. Thread need resources(1MB stack(in .net commited), thread kernel object, etc). Task's are also run parallely as separate thread but it is a system thread pool threads that are optimized by the system considering cpu cores, etc and is used to run many tasks across system. Other than this the task when completed can return an object, so there is convinient way to know what the result of parallel execution is. – Abhijit-K Nov 17 '12 at 09:30
  • @AbhijitKadam When you say "system", are you referring to the .NET framework? – Panzercrisis Sep 02 '16 at 14:06
  • 15
    While this is an interesting read, @MoonKnight, reading a book about threading is a bit of an overkill for a SO question. – Tsahi Asher May 23 '18 at 07:46
  • 2
    @TsahiAsher it is a single chapter _from_ a book. – MoonKnight May 23 '18 at 15:59
  • I can't believe the most upvoted answer has been deleted (I can see it b/c of my big reputation). And there's no way to let mods know they made a mistake – Alex from Jitbit Oct 14 '21 at 18:39

3 Answers3

534

Thread is a lower-level concept: if you're directly starting a thread, you know it will be a separate thread, rather than executing on the thread pool etc.

Task is more than just an abstraction of "where to run some code" though - it's really just "the promise of a result in the future". So as some different examples:

  • Task.Delay doesn't need any actual CPU time; it's just like setting a timer to go off in the future
  • A task returned by WebClient.DownloadStringTaskAsync won't take much CPU time locally; it's representing a result which is likely to spend most of its time in network latency or remote work (at the web server)
  • A task returned by Task.Run() really is saying "I want you to execute this code separately"; the exact thread on which that code executes depends on a number of factors.

Note that the Task<T> abstraction is pivotal to the async support in C# 5.

In general, I'd recommend that you use the higher level abstraction wherever you can: in modern C# code you should rarely need to explicitly start your own thread.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 3
    Even if you are running a message loop-like process you would use a task instead of a thread? – Ignacio Soler Garcia Jan 22 '14 at 14:16
  • 7
    @SoMoS: Probably - you can create it as "long-running" and it will end up with a dedicated thread, but it means using a single abstraction throughout. – Jon Skeet Jan 22 '14 at 14:20
  • 22
    @JonSkeet Also , it's worth to mention that in asp.net - `new Thread()` is not dealing with Threadpool thread , whereas `Task` does use threadpool thread — http://i.stack.imgur.com/O8AnU.jpg – Royi Namir Jun 23 '14 at 12:44
  • 5
    @RoyiNamir: That's not really an ASP.NET-specific thing - and in some cases when you start a task it might use a non-thread-pool thread, if you specify that it's going to be a long-running task. – Jon Skeet Jun 23 '14 at 12:47
  • @JonSkeet can you please point out a few examples when you actually need to start your own thread in modern C#? – Leonid Vasilev Aug 18 '15 at 09:30
  • @Leonid: Not offhand... It does avoid the task scheduler needing to get involved at all... But yes, these days I'd stick to Task.Run. – Jon Skeet Aug 18 '15 at 11:22
  • 2
    @LeonidVasilyev: Not directly Task related (this was before Tasks were introduced), but I did starve the thread pool once doing some image analysis work. I was using (too many really) the thread pool for object detection, but was pushing the results using an SDK which also used the threadpool. This caused my program to lock up because all threads were busy. – Ed S. Aug 23 '17 at 20:01
  • What if I want to use `Task` in realtime system,I need to pause and resume,cancel and stop,does `Task` works even in that harsh cirmustance? – zionpi Apr 30 '19 at 03:32
  • 1
    @zionpi: No, `Task` has no concept of pausing. – Jon Skeet Apr 30 '19 at 06:08
  • 1
    Task is a poor man thread. Running task in same thread as it was called from is not what a high throughput low latency server developer would use ever. – Boppity Bop Jul 13 '19 at 12:38
55

Usually you hear Task is a higher level concept than thread... and that's what this phrase means:

  1. You can't use Abort/ThreadAbortedException, you should support cancel event in your "business code" periodically testing token.IsCancellationRequested flag (also avoid long or timeoutless connections e.g. to db, otherwise you will never get a chance to test this flag). By the similar reason Thread.Sleep(delay) call should be replaced with Task.Delay(delay, token) call (passing token inside to have possibility to interrupt delay).

  2. There are no thread's Suspend and Resume methods functionality with tasks. Instance of task can't be reused either.

  3. But you get two new tools:

    a) continuations

    // continuation with ContinueWhenAll - execute the delegate, when ALL
    // tasks[] had been finished; other option is ContinueWhenAny
    
    Task.Factory.ContinueWhenAll( 
       tasks,
       () => {
           int answer = tasks[0].Result + tasks[1].Result;
           Console.WriteLine("The answer is {0}", answer);
       }
    );
    

    b) nested/child tasks

    //StartNew - starts task immediately, parent ends whith child
    var parent = Task.Factory.StartNew
    (() => {
              var child = Task.Factory.StartNew(() =>
             {
             //...
             });
          },  
          TaskCreationOptions.AttachedToParent
    );
    
  4. So system thread is completely hidden from task, but still task's code is executed in the concrete system thread. System threads are resources for tasks and ofcourse there is still thread pool under the hood of task's parallel execution. There can be different strategies how thread get new tasks to execute. Another shared resource TaskScheduler cares about it. Some problems that TaskScheduler solves 1) prefer to execute task and its conitnuation in the same thread minimizing switching cost - aka inline execution) 2) prefer execute tasks in an order they were started - aka PreferFairness 3) more effective distribution of tasks between inactive threads depending on "prior knowledge of tasks activity" - aka Work Stealing. Important: in general "async" is not same as "parallel". Playing with TaskScheduler options you can setup async tasks be executed in one thread synchronously. To express parallel code execution higher abstractions (than Tasks) could be used: Parallel.ForEach, PLINQ, Dataflow.

  5. Tasks are integrated with C# async/await features aka Promise Model, e.g there requestButton.Clicked += async (o, e) => ProcessResponce(await client.RequestAsync(e.ResourceName)); the execution of client.RequestAsync will not block UI thread. Important: under the hood Clicked delegate call is absolutely regular (all threading is done by compiler).

That is enough to make a choice. If you need to support Cancel functionality of calling legacy API that tends to hang (e.g. timeoutless connection) and for this case supports Thread.Abort(), or if you are creating multithread background calculations and want to optimize switching between threads using Suspend/Resume, that means to manage parallel execution manually - stay with Thread. Otherwise go to Tasks because of they will give you easy manipulate on groups of them, are integrated into the language and make developers more productive - Task Parallel Library (TPL) .

Roman Pokrovskij
  • 9,449
  • 21
  • 87
  • 142
  • 3
    Note - `Thread.Abort` doesn't work for most long operations like DB connections either. It can only abort while in managed code, while most of the long-waiting stuff is stuck in native code (e.g. waiting for a handle, I/O operations...). The only benefit is that it can abort *anywhere* in managed code, relatively safely (e.g. not in `finally` clauses etc.), so it will help against errors like infinite loops etc. Using it in production-level code doesn't make much sense, though. – Luaan Mar 30 '15 at 12:14
  • 3
    `Thread.Abort` is evil and should be avoided wherever possible. Code running under the possibility of a thread abort is incredibly difficult to reason about correctly. It's not worth it, just check some kind of flag. (I'd suggest the `CancellationToken` API, even if you're not using Tasks) – Joren Jun 02 '15 at 12:14
  • It's an error to do so _`Thread.Sleep(delay)` should be replaced with `Task.Delay(delay, token);`_ If, then it should be replaced with `Task.Delay(delay, token).Wait();`, which is the same as `Thread.Sleep(delay)`, or with `await Task.Delay(delay, token)`, if it is possible. – Rekshino Dec 05 '18 at 10:04
43

The Thread class is used for creating and manipulating a thread in Windows.

A Task represents some asynchronous operation and is part of the Task Parallel Library, a set of APIs for running tasks asynchronously and in parallel.

In the days of old (i.e. before TPL) it used to be that using the Thread class was one of the standard ways to run code in the background or in parallel (a better alternative was often to use a ThreadPool), however this was cumbersome and had several disadvantages, not least of which was the performance overhead of creating a whole new thread to perform a task in the background.

Nowadays using tasks and the TPL is a far better solution 90% of the time as it provides abstractions which allows far more efficient use of system resources. I imagine there are a few scenarios where you want explicit control over the thread on which you are running your code, however generally speaking if you want to run something asynchronously your first port of call should be the TPL.

Justin
  • 84,773
  • 49
  • 224
  • 367