Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What happens when you await a Task before returning it?

I am experimenting with the new async and await keywords. I produced the following asynchronous function:

private async static Task<string> GetStringAsync(string pageAddress)
{
    HttpClient client = new HttpClient();
    return client.GetStringAsync(pageAddress);
}

I understand that I am returning a Task<String> and can await the result from another method. This method works fine. My question is what happens (under the hood as it were) when I replace the second line of the above function with the following (notice the introduction of the await keyword):

return await client.GetStringAsync(pageAddress);

The function behaves in exactly the same way! Remember the function returns Task<string> not string. Is the await keyword here degenerate? Does the compiler simply strip it from my code?

like image 625
Caster Troy Avatar asked Dec 06 '22 06:12

Caster Troy


2 Answers

The answer to this question is too large to post here given your likely current level of understanding. What you should do is start by reading my MSDN article and then Mads' MSDN article; they are a good beginner introduction to the feature and Mads describes how it is implemented. You can find links here:

http://blogs.msdn.com/b/ericlippert/archive/2011/10/03/async-articles.aspx

Then if you are interested in the theory underlying the feature you should start by reading all my articles on continuation passing style:

http://blogs.msdn.com/b/ericlippert/archive/tags/continuation+passing+style/

Start from the bottom. Once you understand the notion of continuation, you can then read my series of articles on how we designed the async feature:

http://blogs.msdn.com/b/ericlippert/archive/tags/async/

like image 84
Eric Lippert Avatar answered Dec 09 '22 16:12

Eric Lippert


As Eric Lippert pointed out, the first version won't compile; you have to remove the async keyword or you'll get a type error.

Here's a useful mental model regarding how the async and await keywords work with the return type:

  • Any value T returned by an async method is "wrapped" into a Task<T>.
  • The await keyword (which you can think of as an operator), when applied to a Task<T>, will "unwrap" it, resulting in a value of type T.

Now, that's an extreme simplification; what's actually happening is more complicated. E.g., this simplification skips over how await works with the current SynchronizationContext: in the second example, the method will attempt to return to the original context after the await completes, so you will observe different behavior if that context is busy.

But for the most part, the two examples are almost equivalent. The second one is less efficient due to the async state machine and resuming on the context.

I have an async/await intro that you may find helpful; in that post I try to explain async in a way that is not too complex but also not actually incorrect. :)

like image 32
Stephen Cleary Avatar answered Dec 09 '22 15:12

Stephen Cleary