Imagine you are a student who needs to study for three exams in one week. You decide to study for each exam one after the other. However, you realize that this will take a lot of time, and you might not have enough time to study for all the exams.
This is where the async and await keywords come in handy.
To better understand this, let's consider the story of a chef who is preparing a meal in a busy restaurant.
The chef has to cook several dishes simultaneously to meet the demands of the customers. To do this efficiently, the chef uses an asynchronous cooking technique where he starts washing a dish, sets a timer, and moves on to the next dish while the first one is cooking.
In programming, async and await work similarly to the chef's cooking technique. When a method is marked as async, it can execute non-blocking operations without blocking the calling thread. The await keyword can be used to pause the execution of the method until the asynchronous operation is complete.
Let's take a closer look at how this works with examples.
Example 1: Synchronous Method
Suppose you have a method that calculates the sum of two numbers synchronously. Here's an example:
public int Sum(int a, int b)
{
return a + b;
}
In this example, the Sum method takes two integers as input and returns their sum synchronously. If you call this method, the calling thread will be blocked until the calculation is complete.
Example 2: Asynchronous Method
Suppose you have a method that calculates the sum of two numbers asynchronously. Here's an example:
public async Task<int> SumAsync(int a, int b)
{
await Task.Delay(1000);
return a + b;
}
In this example, the SumAsync method takes two integers as input and returns their sum asynchronously. We mark the method as async to indicate that it contains asynchronous code.
Inside the method, we use the await keyword to pause the execution of the method for 1 second to simulate a non-blocking operation. When the 1-second delay is complete, we return the sum of the two numbers.
Example 3: Using Asynchronous Method
Suppose you want to use the SumAsync method to calculate the sum of two numbers. Here's an example:
public async void CalculateSum()
{
int sum = await SumAsync(2, 3);
Console.WriteLine(sum);
}
In this example, we define a method called CalculateSum that uses the SumAsync method to calculate the sum of two numbers. We mark the method as async to indicate that it contains asynchronous code.
Inside the method, we call the SumAsync method and use the await keyword to pause the execution of the method until the asynchronous operation is complete. When the operation is complete, we assign the result to the sum variable and print it to the console.
Example 4: Asynchronous Web Request
Suppose you want to make an asynchronous web request to get data from an API. Here's an example:
public async Task<string> GetApiDataAsync()
{
string url = "https://example.com/api/data";
using (HttpClient client = new HttpClient())
{
HttpResponseMessage response = await client.GetAsync(url);
response.EnsureSuccessStatusCode();
string data = await response.Content.ReadAsStringAsync();
return data;
}
}
In this example, we define a method called GetApiDataAsync that makes an asynchronous web request to get data from an API. We use the HttpClient class to send an HTTP GET request to the specified URL.
We use the await keyword to pause the execution of the method until the asynchronous operation is complete. When the operation is complete, we read the response data as a string and return it.
Example 5: Asynchronous File I/O
Suppose you want to read data from a file asynchronously. Here's an example:
public async Task<string> ReadFileAsync(string filePath)
{
using (StreamReader reader = new StreamReader(filePath))
{
string data = await reader.ReadToEndAsync();
return data;
}
}
In this example, we define a method called ReadFileAsync that reads data from a file asynchronously. We use the StreamReader class to read data from the specified file.
We use the await keyword to pause the execution of the method until the asynchronous operation is complete. When the operation is complete, we read the file contents as a string and return it.
Example 6: Parallel Asynchronous Execution
Suppose you want to execute multiple asynchronous tasks in parallel. Here's an example:
public async Task<int[]> GetResultsAsync()
{
Task<int> task1 = SumAsync(2, 3);
Task<int> task2 = SumAsync(4, 5);
Task<int> task3 = SumAsync(6, 7);
int[] results = await Task.WhenAll(task1, task2, task3);
return results;
}
In this example, we define a method called GetResultsAsync that executes multiple asynchronous tasks in parallel. We use the SumAsync method from Example 2 to calculate the sum of two numbers asynchronously.
We create three tasks to execute the SumAsync method with different input parameters. We use the Task.WhenAll method to wait for all the tasks to complete asynchronously.
We use the await keyword to pause the execution of the method until all the asynchronous operations are complete. When all the operations are complete, we return an array of results.
Example 7: Asynchronous Database Query
Suppose you want to make an asynchronous database query to get data from a database. Here's an example:
public async Task<List<string>> GetNamesAsync()
{
List<string> names = new List<string>();
using (SqlConnection connection = new SqlConnection(connectionString))
{
await connection.OpenAsync();
SqlCommand command = new SqlCommand("SELECT Name FROM Customers", connection);
SqlDataReader reader = await command.ExecuteReaderAsync();
while (await reader.ReadAsync())
{
string name = reader.GetString(0);
names.Add(name);
}
}
return names;
}
In this example, we define a method called GetNamesAsync that makes an asynchronous database query to get a list of names from a Customers table in a database.
We use the SqlConnection class to create a connection to the database and the SqlCommand class to create a SQL command to retrieve the data.
We use the await keyword to pause the execution of the method until the asynchronous operations are complete. We use the OpenAsync method of the SqlConnection class to open the database connection asynchronously, and the ExecuteReaderAsync method of the SqlCommand class to execute the SQL query asynchronously.
We use a SqlDataReader object to read the data returned by the SQL query asynchronously. We use the ReadAsync method to read the data row-by-row, and the GetString method to get the value of the first column in the row as a string.
We add each name to a List and return the list of names when all the data has been read from the SqlDataReader.
Conclusion
In conclusion, async and await are powerful features in C# that allow developers to write efficient and responsive code that can execute non-blocking I/O operations and efficiently utilize system resources. These examples demonstrate how async and await can be used in various scenarios to write asynchronous code that is easy to read and maintain.
Top comments (1)
Hey Hootan Hemmati, this is an awesome blog on async and await and I just learned a clear and best from the post and can use it anywhere irrespective of language. Thanks for your effort and hope to see more blogs like these. Keep it up 👍