Asynchronous programming maximizes utilization of resources on multicore systems, by allowing units of work to be separated and completed.
It frees up the calling system, especially a user interface, as to not wait for long operations.
Async and await simplify asynchronous programming
Async and await allow asynchronous code to resemble the structure of synchronous code.
The async keyword instructs the compiler to allow await.
Methods marked with async may return Task
The await keyword instructs the method to return.
The await keyword instructs the complier to resume execution within the same context after the operation is complete.
An event handler calls and awaits the AccessTheWebAsync async method.
AccessTheWebAsync creates an HttpClient instance and calls the GetStringAsync asynchronous method to download the contents of a website as a string.
Something happens in GetStringAsync that suspends its progress. Perhaps it must wait for a website to download or some other blocking activity. To avoid blocking resources, GetStringAsync yields control to its caller, AccessTheWebAsync. GetStringAsync returns a Task where TResult is a string, and AccessTheWebAsync assigns the task to the getStringTask variable. The task represents the ongoing process for the call to GetStringAsync, with a commitment to produce an actual string value when the work is complete.
Because getStringTask hasn’t been awaited yet, AccessTheWebAsync can continue with other work that doesn’t depend on the final result from GetStringAsync. That work is represented by a call to the synchronous method DoIndependentWork.
DoIndependentWork is a synchronous method that does its work and returns to its caller.
AccessTheWebAsync has run out of work that it can do without a result from getStringTask. AccessTheWebAsync next wants to calculate and return the length of the downloaded string, but the method can’t calculate that value until the method has the string.Therefore, AccessTheWebAsync uses an await operator to suspend its progress and to yield control to the method that called AccessTheWebAsync. AccessTheWebAsync returns a Task to the caller. The task represents a promise to produce an integer result that’s the length of the downloaded string.Inside the caller (the event handler in this example), the processing pattern continues. The caller might do other work that doesn’t depend on the result from AccessTheWebAsync before awaiting that result, or the caller might await immediately. The event handler is waiting for AccessTheWebAsync, and AccessTheWebAsync is waiting for GetStringAsync.
GetStringAsync completes and produces a string result. The string result isn’t returned by the call to GetStringAsync in the way that you might expect. (Remember that the method already returned a task in step 3.) Instead, the string result is stored in the task that represents the completion of the method, getStringTask. The await operator retrieves the result from getStringTask. The assignment statement assigns the retrieved result to urlContents.
When AccessTheWebAsync has the string result, the method can calculate the length of the string. Then the work of AccessTheWebAsync is also complete, and the waiting event handler can resume. In the full example at the end of the topic, you can confirm that the event handler retrieves and prints the value of the length result.