08 Feb 2024
In C#, async and await are features introduced in C# 5.0 to simplify asynchronous programming. They are used to write asynchronous code in a more natural and readable way without blocking the execution of the calling thread.
Here's a brief explanation of async and await:
-
async:
asyncis used as a modifier for methods. It indicates that the method contains asynchronous operations. An async method can contain one or moreawaitexpressions. -
await:
awaitis used to pause the execution of an async method until the awaited task completes. When the awaited task finishes, the execution of the method resumes. The await keyword can only be used inside methods marked with the async modifier.
Asynchronous programming:
In asynchronous programming with async and await in C#, the thread that executes the asynchronous method is not blocked while waiting for the result of the asynchronous operation. However, the continuation of the method after the await keyword does wait for the result.
When you use await, the method essentially splits into two parts:
- The part before the
awaitkeyword, which executes synchronously up to theawaitpoint. - The part after the
awaitkeyword, which is a continuation that executes asynchronously when the awaited operation completes.
While the awaited operation is in progress, the thread that originally executed the method is freed up to do other work.
The await keyword itself doesn't block the execution of the method. Instead, it tells the compiler to automatically generate code to set up a callback to resume the method when the awaited operation completes.
So, while the thread executing the method is not waiting for the result, the continuation of the method (the code after the await statement) is waiting for the result to proceed. This allows for non-blocking asynchronous execution and efficient use of system resources.
Example 1
Below is an example of an async method that contains four await statements:
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
await ExampleAsync();
}
static async Task ExampleAsync()
{
// Simulate asynchronous operations with four await statements
await Task.Delay(1000); // Wait for 1 second
Console.WriteLine("First await completed.");
await Task.Delay(2000); // Wait for 2 seconds
Console.WriteLine("Second await completed.");
await Task.Delay(3000); // Wait for 3 seconds
Console.WriteLine("Third await completed.");
await Task.Delay(4000); // Wait for 4 seconds
Console.WriteLine("Fourth await completed.");
}
}
In the provided program, the control flow moves through the asynchronous method ExampleAsync() and the await statements in the following manner:
-
Main Method Entry:
- The
Mainmethod is marked asasync, allowing it to call asynchronous methods usingawait. await ExampleAsync()is called, initiating the asynchronous execution of theExampleAsyncmethod.
- The
-
ExampleAsync Method Execution:
ExampleAsyncmethod is entered.- The first
awaitstatement is encountered:await Task.Delay(1000);. - The
Task.Delay(1000)method is invoked, which asynchronously delays execution by 1000 milliseconds (1 second). - The control returns to the caller (
Mainmethod) while the delay is in progress.
-
Control Returns to Main:
- As the first
awaitis encountered, control returns to theMainmethod, and it awaits the completion of theExampleAsyncmethod.
- As the first
-
ExampleAsync Resumes Execution:
- After 1 second, the first
awaitinExampleAsynccompletes, and the method resumes execution. - The console outputs "First await completed."
- The second
awaitstatement is encountered:await Task.Delay(2000);. - Another asynchronous delay of 2000 milliseconds (2 seconds) is initiated.
- Control returns to the caller (
Mainmethod) while the delay is in progress.
- After 1 second, the first
-
Control Returns to Main Again:
- As the second
awaitis encountered, control returns to theMainmethod, and it awaits the completion of theExampleAsyncmethod.
- As the second
-
ExampleAsync Resumes Execution Again:
- After 2 seconds, the second
awaitinExampleAsynccompletes, and the method resumes execution. - The console outputs "Second await completed."
- The same pattern repeats for the third and fourth
awaitstatements, each time initiating a delay and returning control to the caller.
- After 2 seconds, the second
-
Finalization:
- After all four
awaitstatements have completed, theExampleAsyncmethod finishes executing. - The
Mainmethod completes awaiting theExampleAsyncmethod. - The program ends its execution.
- After all four
This flow demonstrates how asynchronous programming in C# allows non-blocking execution, where the method can await the completion of asynchronous operations while allowing the thread to be freed up for other tasks.
Example 2
Here's a basic example to illustrate how async and await are used:
using System;
using System.Net.Http;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
await DoSomethingAsync();
}
static async Task DoSomethingAsync()
{
// Simulate an asynchronous operation, such as making an HTTP request
HttpClient client = new HttpClient();
string url = "https://jsonplaceholder.typicode.com/posts/1";
// Await the completion of the HTTP request
HttpResponseMessage response = await client.GetAsync(url);
// Once the response is received, read the content
string content = await response.Content.ReadAsStringAsync();
// Output the content
Console.WriteLine(content);
}
}
In the example provided, when you use await with an asynchronous operation like GetAsync and ReadAsStringAsync from HttpClient, the executing thread is not blocked while waiting for the operation to complete.
Here's what happens under the hood:
-
When you call an asynchronous method marked with
async, such asGetAsync, it initiates the operation (in this case, an HTTP request) asynchronously. This means that the method starts executing, but it doesn't block the thread while waiting for the operation to complete. -
When you use
awaitwith an asynchronous operation, likeawait client.GetAsync(url), the method is paused at that point, and the control is returned to the caller (in this case,Mainmethod). This means that the thread executing the method is freed up to do other work. -
While the asynchronous operation (e.g., HTTP request) is in progress, the thread is free to do other tasks, like responding to user input, handling other requests, etc.
-
When the awaited operation completes (in this case, when the HTTP request finishes), the method resumes execution after the
awaitstatement.
In summary, using async and await does not block the thread. Instead, it allows the thread to be freed up to perform other tasks while the asynchronous operation is in progress. This makes asynchronous programming in C# more efficient and scalable, especially in scenarios where you have many concurrent operations or need to maintain responsiveness in user interfaces.