In fact, you get only the second set of benefits in both cases. await does not start asynchronous execution of anything, it is just a keyword for the compiler to generate code to handle completion, context, etc.
You can find a better explanation of this in "Call the method with the wait" ... ugh! 'from Stephen Toub.
Up to the asynchronous method itself, to decide how it achieves asynchronous execution:
- Some methods will use the task to run their code in the ThreadPool thread.
- Some will use some mechanism for completing I / O. There is even a special ThreadPool for this, which you can use with Tasks using the custom TaskScheduler
- Some of them wrap the TaskCompletion object through another mechanism, such as events or callbacks.
In each case, a particular implementation frees the thread (if used). TaskScheduler automatically frees the thread when the task completes execution, so you get this functionality for cases No. 1 and No. 2 in any case.
What happens in case # 3 for callbacks depends on how the callback is made. In most cases, the callback is executed in a thread controlled by some external library. In this case, you need to quickly process the callback and return so that the library can reuse this method.
EDIT
Using the decompiler, you can see that GetStringAsync uses the third option: it creates a TaskCompletion source that receives a signal when the operation completes. The execution of the operation is delegated to the HttpMessageHandler.
source share