Task vs Thread differences [duplicate]
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.
Usually you hear Task is a higher level concept than thread... and that's what this phrase means:
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 reasonThread.Sleep(delay)
call should be replaced withTask.Delay(delay, token)
call (passing token inside to have possibility to interrupt delay).There are no thread's
Suspend
andResume
methods functionality with tasks. Instance of task can't be reused either.-
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 );
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
.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 ofclient.RequestAsync
will not block UI thread. Important: under the hoodClicked
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) .
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.