Reputation: 2866
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?
Upvotes: 4
Views: 591
Reputation: 456497
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:
T
returned by an async
method is "wrapped" into a Task<T>
.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. :)
Upvotes: 6
Reputation: 311865
Eric's obviously the expert here and his advice is sound, but to answer your specific question:
In the first version, the async
keyword on the method is irrelevant and your GetStringAsync
method returns the same Task<string>
awaitable that's returned by client.GetStringAsync
.
In the second version, the async
keyword on the method is required because you're using await
in the method and the await
keyword creates and returns a separate Task<string>
awaitable that completes once the awaitable from client.GetStringAsync
completes. When that occurs, the await
then evaluates to the string that was asynchronously obtained by client.GetStringAsync
which is returned as the result of your asynchronous method.
So to the caller of GetStringAsync
, they're functionally the same, but the first version is cleaner.
Upvotes: 2
Reputation: 660058
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/
Upvotes: 7