Task vs Thread differences

349,814

Solution 1

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.

Solution 2

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) .

Solution 3

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.

Share:
349,814
Jacek
Author by

Jacek

ASP.NET programmer

Updated on July 19, 2022

Comments

  • Jacek
    Jacek almost 2 years

    I'm new to parallel programming. There are two classes available in .NET: Task and Thread.

    So, my questions are:

    • What is the difference between those classes?
    • When is it better to use Thread over Task (and vice-versa)?
    • MoonKnight
      MoonKnight over 11 years
      Read this.
    • Abhijit-K
      Abhijit-K over 11 years
      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.
    • Panzercrisis
      Panzercrisis over 7 years
      @AbhijitKadam When you say "system", are you referring to the .NET framework?
    • Tsahi Asher
      Tsahi Asher almost 6 years
      While this is an interesting read, @MoonKnight, reading a book about threading is a bit of an overkill for a SO question.
    • MoonKnight
      MoonKnight almost 6 years
      @TsahiAsher it is a single chapter from a book.
    • Alex from Jitbit
      Alex from Jitbit over 2 years
      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
  • Ignacio Soler Garcia
    Ignacio Soler Garcia over 10 years
    Even if you are running a message loop-like process you would use a task instead of a thread?
  • Jon Skeet
    Jon Skeet over 10 years
    @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.
  • Royi Namir
    Royi Namir almost 10 years
    @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 — i.stack.imgur.com/O8AnU.jpg
  • Jon Skeet
    Jon Skeet almost 10 years
    @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.
  • Luaan
    Luaan about 9 years
    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.
  • Joren
    Joren almost 9 years
    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)
  • Leonid Vasilev
    Leonid Vasilev over 8 years
    @JonSkeet can you please point out a few examples when you actually need to start your own thread in modern C#?
  • Jon Skeet
    Jon Skeet over 8 years
    @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.
  • Ed S.
    Ed S. over 6 years
    @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.
  • Rekshino
    Rekshino over 5 years
    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.
  • zionpi
    zionpi about 5 years
    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?
  • Jon Skeet
    Jon Skeet about 5 years
    @zionpi: No, Task has no concept of pausing.
  • Boppity Bop
    Boppity Bop almost 5 years
    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.