In .NET (and .NET Core), async and await are keywords used to implement asynchronous programming. They enable methods to execute non-blocking operations, such as performing I/O tasks or waiting for long-running operations, without freezing the application or consuming unnecessary resources.
Non-Blocking Operations
Asynchronous programming allows you to perform tasks without blocking the main thread. This is particularly useful in applications with a user interface (UI) where blocking the main thread can make the UI unresponsive.
For example, if you are making a network
request to fetch data from a server, using async
and await
allows
the application to continue executing other tasks while waiting for the
server response.
Improved Performance
Asynchronous methods help improve the performance of your application by utilizing system resources more efficiently. Instead of waiting for a task to complete, the system can switch to other tasks, making better use of CPU cycles.
This is crucial for web applications where multiple requests can be handled concurrently.
Benefit | Explanation |
---|---|
Non-blocking I/O | Frees threads to handle other operations while waiting for I/O-bound tasks. |
Scalability | Supports high concurrency with fewer threads, improving application scalability. |
Readability | Simplifies asynchronous code, making it easier to understand and maintain. |
Responsiveness | Keeps UI or server threads responsive during lengthy operations. |
Error Handling | Integrates with try-catch for structured exception handling in async methods. |
public string GetData()
{
Thread.Sleep(5000); // Simulate long operation
return "Data retrieved";
}
Console.WriteLine(GetData()); // Blocks for 5 seconds
Asynchronous Example (Non-Blocking)
public async Task<string> GetDataAsync()
{
await Task.Delay(5000); // Simulate long operation asynchronously
return "Data retrieved";
}
public async Task ExecuteAsync()
{
string result = await GetDataAsync(); // Non-blocking
Console.WriteLine(result);
}
Here,
Common Use Cases for async and await
1. Database Queries
var data = await dbContext.Users.ToListAsync();
2. File I/O
var content = await File.ReadAllTextAsync("file.txt");
3. Web Requests
var response = await httpClient.GetStringAsync("https://example.com");
4. Background Operations
await Task.Run(() => PerformHeavyComputation());
Please have a look at the below example. It’s a very simple example. Inside the main method, first, we print that main method started, then we call the OtherMethod. Inside the OtherMethod, first, we print that OtherMethod started and then the thread execution is sleep for 5. After 5 seconds, it will wake up and execute the other statement inside the OtherMethod method. Then it will come back to the main method, where we called OtherMethod. And finally, it will execute the last print statement inside the main method.
Example
using System;
using System.Threading;
namespace AsynchronousProgramming
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Main Method Started......");
OtherMethod();
Console.WriteLine("Main Method End");
Console.ReadKey();
}
public static void OtherMethod()
{
Console.WriteLine("Other Method Started......");
Thread.Sleep(TimeSpan.FromSeconds(5));
Console.WriteLine("\n");
Console.WriteLine("Other Method End");
}
}
}
Output
When you execute the above code, you will see that after printing OtherMethod Started……, the console window is frozen for 5 seconds. This is because here we are not using asynchronous programming. One thread i.e. the Main thread is responsible for executing the code And when we call Thread.Sleep method the current thread is blocked for 5 seconds. This is a bad user experience.
Now, let us see how we can overcome this problem by using asynchronous programming.
Async and Await Keyword
Please have a look at the below image. The Thread.Sleep() is a synchronous method. So, we have changed this to Task.Delay() which is an asynchronous method. The Task.Delay() method exactly does the same thing as Thread.Sleep() does.
And, if we want to wait for the task i.e. Task.Delay to be done, then we have to use the await operator. As we said earlier the await operator is going to release the current thread that is running from having to wait for this operation. Therefore, that thread is going to be available for all our tasks. And then after 5 seconds, the thread will be called to the place (i.e. Task.Delay()) in order to run the rest code of the OtherMethod. As we have used await keyword inside the OtherMethod, we must have to make the OtherMethod as asynchronous as using the async keyword.
It is important to realize that await does not mean that the thread will have to be blocked waiting for the operation. Await means the thread is free to go to do another thing and then he will come back when this operation (in our example Task.Dealy i.e. after 5 seconds) is done. The following example code exactly does the same thing.
Example
using System;
using System.Threading.Tasks;
namespace AsynchronousProgramming
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Main Method Started......");
OtherMethod();
Console.WriteLine("Main Method End");
Console.ReadKey();
}
public async static void OtherMethod()
{
Console.WriteLine("Other Method Started......");
//Thread.Sleep(TimeSpan.FromSeconds(5));
await Task.Delay(TimeSpan.FromSeconds(5));
Console.WriteLine("\n");
Console.WriteLine("Other Method End");
}
}
}
Output
Now, if you run the above code, then you will see that after printing the Other Method Started when the statement Task.Dealy() executed, it will free the current thread, and then that current thread comes and execute the rest of the code inside the main method. And after 5 seconds again thread come back to the Other Method and execute the rest of the code inside the SomeMethod.