Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between Task and async Task

Tags:

C# provides two ways of creating asynchronous methods:

Task():

static Task<string> MyAsyncTPL() {
  Task<string> result = PerformWork();
  return result.ContinueWith(t => MyContinuation());
}

async Task():

static async Task<string> MyAsync() {
  string result = await PerformWork();
  return MyContinuation();
}

Both of the above methods are async and achieve the same thing. So, when should I choose one method over the other? Are there any guidelines or advantages of using one over the other?

like image 965
Chander Shivdasani Avatar asked Apr 10 '14 19:04

Chander Shivdasani


People also ask

What is the difference between Task and async Task?

Async methods are intended to be non-blocking operations. An await expression in an async method doesn't block the current thread while the awaited task is running. Instead, the expression signs up the rest of the method as a continuation and returns control to the caller of the async method.

What is Task and async?

Async code uses Task<T> and Task , which are constructs used to model work being done in the background. The async keyword turns a method into an async method, which allows you to use the await keyword in its body.

What is Task in async and await?

async, await, and Task The await keyword waits for the async method until it returns a value. So the main application thread stops there until it receives a return value. The Task class represents an asynchronous operation and Task<TResult> generic class represents an operation that can return a value.

Can I use Task without async?

If you use await in your code, you are required to use the async keyword on the method. If you use async and want to return an actual type, you can declare that your method returns the type as a generic Task like this Task<int> . Task<TResult> , for an async method that returns a value.


2 Answers

I recommend you use await rather than ContinueWith. While - at a high level - they are very similar, they also have different default behavior.

When you use ContinueWith, you are choosing a lower-level abstraction. In particular, here are some "danger points", and this is why I don't recommend using ContinueWith unless the method is really simple (or your name is Stephen Toub):

  • Exceptions raised from async Task methods are placed on the returned task; exceptions raised from non-async methods are propagated directly.
  • await will by default will resume the async method in the same "context". This "context" is SynchronizationContext.Current unless it is null, in which case it is TaskScheduler.Current. This means that if you call MyAsync on a UI thread (or within an ASP.NET request context), then MyContinuation will also execute on the UI thread (or in that same ASP.NET request context). I explain this more on my blog.
  • You should always specify a scheduler for ContinueWith; otherwise, it will pick up TaskScheduler.Current, which can cause surprising behavior. I describe this problem in detail on my blog. That post is about StartNew; but ContinueWith has the same "non-default default scheduler" problem described in that post.
  • await uses appropriate behavior and optimization flags that are not set by default in ContinueWith. For example, it uses DenyChildAttach (to ensure asynchronous tasks are not mistakenly used as parallel tasks) and ExecuteSynchronously (an optimization).

In short, the only reason to use ContinueWith for asynchronous tasks is to save an extremely small amount of time and memory (by avoiding the async state machine overhead), and in exchange your code is less readable and maintainable.

With an extremely simple example, you might get away with it; but as Jon Skeet pointed out, as soon as you have loops the ContinueWith code simply explodes in complexity.

like image 73
Stephen Cleary Avatar answered Sep 30 '22 16:09

Stephen Cleary


await is basically a shorthand for the continuation, by default using the same synchronization context for the continuation.

For very simple examples like yours, there's not much benefit in using await - although the wrapping and unwrapping of exceptions makes for a more consistent approach.

When you've got more complicated code, however, async makes a huge difference. Imagine you wanted:

static async Task<List<string>> MyAsync() {
    List<string> results = new List<string>();
    // One at a time, but each asynchronously...
    for (int i = 0; i < 10; i++) {
        // Or use LINQ, with rather a lot of care :)
        results.Add(await SomeMethodReturningString(i));
    }
    return results;
}

... that gets much hairier with manual continuations.

Additionally, async/await can work with types other than Task/Task<T> so long as they implement the appropriate pattern.

It's worth reading up more about what it's doing behind the scenes. You might want to start with MSDN.

like image 35
Jon Skeet Avatar answered Sep 30 '22 17:09

Jon Skeet