Asynchronous Programming with async/await in C# (with simple example)
Asynchronous programming with async
and await
keywords in C# allows you to write code that can execute concurrently(parallelly) without blocking the main executing thread.
It enables you to handle time-consuming operations efficiently, such as network requests, database queries, or file I/O, without freezing the user interface or causing unnecessary delays.
Why asynchronous programming:
Synchronous programming executes the code line by line and the current task must be completed before moving to the next task. In general, it is slow and may not be suitable for time-consuming operations.
Key parts of async/await:
async
Modifier: When you mark a method with theasync
modifier, you indicate that it contains asynchronous operations. This allows you to use theawait
keyword inside the method.await
Keyword: Theawait
keyword is used to indicate that a particular operation should be awaited, allowing the calling code to proceed without blocking. It can only be used within anasync
method.Asynchronous Method Signature: An asynchronous method typically returns a
Task
orTask<T>
, representing an asynchronous operation that may produce a result. TheT
denotes the type of the result if applicable.
Example of a simple asynchronous method:
public async Task PrepareTeaAsync()
{
Console.WriteLine("Preparing Tea");
await Task.Delay(3000);
}
In this example, the PrepareTeaAsync
method is marked as async
, indicating that it contains asynchronous operation. It uses await
keyword to wait for the task completion. Task.Delay
is used here to simulate an asynchronous task.
Here's an example to illustrate the difference between synchronous and asynchronous programming.
internal class Program
{
static void Main(string[] args)
{
var stopwatch = new Stopwatch();
Console.WriteLine("Bakery inc. Serving tea with snacks. Select serving speed - 1. Normal 2. Speed");
switch (Console.ReadLine())
{
case "1":
stopwatch.Start();
PrepareTea();
PrepareSnacks();
break;
case "2":
stopwatch.Start();
var teaTask = PrepareTeaAsync();
var snacksTask = PrepareSnacksAsync();
Task.WaitAll(teaTask, snacksTask);
break;
}
stopwatch.Stop();
Console.WriteLine($"Serving Tea with snacks (Waiting time - {stopwatch.Elapsed})");
}
private static void PrepareTea()
{
Console.WriteLine("Preparing Tea");
Task.Delay(3000).Wait();
}
private static void PrepareSnacks()
{
Console.WriteLine("Arranging snacks");
Task.Delay(3000).Wait();
}
private static async Task PrepareTeaAsync()
{
Console.WriteLine("Preparing Tea");
await Task.Delay(3000);
}
private static async Task PrepareSnacksAsync()
{
Console.WriteLine("Arranging snacks");
await Task.Delay(3000);
}
}
In the above program, we used two options 1. normal (synchronous) 2. quick (asynchronous). Each option calls two methods with the same operations but later one additionally using async/await
.
Normal: This synchronous option is called two methods
PrepareTea()
andPrepareSnacks()
. The first method takes 3 seconds to complete and the second method starts executing once the first method is completed. The latter method was completed after 3 seconds.The above output shows, the total time taken to complete the synchronous operation is 6 seconds.
Speed: This asynchronous option is called two methods
PrepareTeaAsync()
andPrepareSnacksAsync()
. Both methods started at the same time and each takes 3 seconds.Task.WaitAll
waits for the two methods to complete.The above output shows, the total time taken to complete the asynchronous operation is 3 seconds. Since both methods started at the same time and ran in parallel, the total time is gradually reduced (almost half of synchronous!)
Asynchronous programming with async
and await
simplifies working with asynchronous operations, improves code readability, and enhances the responsiveness of applications by avoiding blocking calls. It is a powerful feature in C# for efficiently handling I/O-bound operations and making efficient use of system resources.