Asynchronous programming in C# is a powerful way for creating efficient and responsive applications, it aims to improve the efficiency and responsiveness of applications by allowing multiple tasks to run concurrently. In this blog post, we’ll explore detail about the Asynchronous programming in C#.
What is asynchronous programming?
In traditional Synchronous programming, task executes one after other, your program waits for a task to finish before moving on to the next task.
For example: Waiting in a queue at a ticket counter; you have to wait for the person in front of you to finish buying their ticket before your turn.
On the other hand, Asynchronous programming changes that approach. Instead of waiting for one task to finish before starting another, it allows your program to start a task, and while it’s working on that, it can do something else.
For Example: It’s like having more than one worker in a kitchen, where each worker can handle a different task and each task are happening at the same time.
Let’s take a scenario where applications need to perform operations that take time, such as reading from a file or external drive, making a network request to access some resource, or querying a database.
In Synchronous code, the application would wait until the operation is complete, which could lead to unresponsiveness. Asynchronous programming addresses this challenge by allowing the application to continue executing other tasks while waiting for the time-consuming operation to finish.
Asynchronous vs. Synchronous Programming:
Here are the key differences between Asynchronous and Synchronous programming.
Asynchronous Programming |
Synchronous Programming |
---|---|
It allows tasks to execute concurrently, that enables multiple operations to happen at the same time. | In this case, Tasks are executed sequentially; the program waits for each task to finish before moving on to the next one. |
Asynchronous tasks do not block the program’s execution, the program can continue executing other operations while waiting for the task to complete. | Synchronous tasks block the program’s execution. When a synchronous task is initiated, the program waits until the task is finished before proceeding to the next line of code. |
It enhances the responsiveness of an application and prevents the program from freezing. | It can make an application less responsive; the program may appear frozen or unresponsive until the current task is completed. |
Asynchronous programming can utilize system resources more efficiently. | Synchronous programming uses system resources sequentially, each task occupies resources exclusively until it completes current task. |
Implementation of Asynchronous Programming in C#:
1) Async and Await Pattern:
The asyncand awaitpattern is the most common and widely used approach for implementing Asynchronous programming in C#. It allows you to write asynchronous programming code in a more readable and sequential manner. Here’s how it works:
- Mark the method with the async keyword to indicate that it contains asynchronous code.
- Use the await keyword before an asynchronous operation to pause the method execution until the awaited operation completes.
- The method should return a Task or Task<T> to represent the asynchronous operation’s completion.
Let’s dive into an example to understand how asynchronous programming works in C#.NET. Consider a scenario where you need to fetch data from a website page. Here’s how you can accomplish it using asyncand await:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
using System; using System.Net; using System.Net.Http; using System.Threading.Tasks; namespace AsyncAwaitDemo { class Program { public static async Task Main() { Console.WriteLine("Start program."); // Asynchronous method call with 'await' string websitedata = await FetchExternalWebsiteDataAsync(); // The program will not wait for the method above to finish // It will continue executing here and print the next line. Console.WriteLine("Program didnt wait for the above method to complete and print this line !"); Console.WriteLine("Data Extracted Asynchronously: " + websitedata); Console.WriteLine("End program."); } public static async Task<string> FetchExternalWebsiteDataAsync() { ServicePointManager.Expect100Continue = true; ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; using (HttpClient client = new HttpClient()) { string websiteUrl = "https://thedotnetguide.com/privacy-policy/"; HttpResponseMessage response = await client.GetAsync(websiteUrl); string websitedata = await response.Content.ReadAsStringAsync(); return websitedata; } } } } |
In this above example,
- The Main method is marked as async, allowing us to use await inside it. The FetchExternalWebsiteDataAsync method, responsible for fetching data from a website which is also marked as async.
- In this case, the program continues executing and prints the line “Program didn’t wait for the above method to complete and print this line!” while waiting for the async call to complete.
If we run above program, then it produces below output.

2) Task-based Asynchronous Pattern (TAP):
The Task-based Asynchronous Pattern is another approach for asynchronous programming. It involves returning a Task or Task<T> from a method to represent an asynchronous operation. The caller can then awaitthe task to get the operation’s result.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
using System; using System.Threading.Tasks; namespace TaskbasedAsynchronousPatternDemo { class Program { public static async Task Main() { Console.WriteLine("Start of the program."); // Asynchronous method call with Task-based pattern Task<string> dataTask = GetExternalDataAsync(); // Do other tasks while waiting for the data Console.WriteLine("Doing some other tasks by printing this line."); // Wait for the data task to complete and get the result string data = await dataTask; Console.WriteLine("Data : " + data); Console.WriteLine("End of the program."); } public static async Task<string> GetExternalDataAsync() { await Task.Delay(2000); // Simulating an asynchronous operation by delaying a 2 second return "Sample data from GetExternalDataAsync() method"; } } } |
In this above example,
- We have the Main method marked as async to allow the use of await. Inside Main, we call the GetExternalDataAsync method, which returns a Task<string>.
- This Task represents the asynchronous operation of fetching data. While waiting for the data, we simulate doing some other tasks by printing “Doing some other tasks by printing this line.” to the console. The await keyword is then used to wait for the dataTask to complete and retrieve the result.
- The GetExternalDataAsync method is also marked as async. It uses await Task.Delay(2000) to simulate an asynchronous operation that takes 2 seconds. Finally, it returns the string “Sample data from GetSimulationDataAsync() method” as the result.
When you run the program, it will print the following output:

3) Event-based Asynchronous Pattern (EAP):
The Event-based Asynchronous Pattern is commonly used with older APIs that follow an event-driven model. It involves registering event handlers for asynchronous operations and handling the completion or progress events.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
using System; using System.Net; namespace EventBasedAsynPatternDemp { class Program { public static void Main() { Console.WriteLine("Start of the EventBasedAsynPatternDemp program."); // Create a WebClient instance WebClient client = new WebClient(); ServicePointManager.Expect100Continue = true; ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; // Subscribe to the DownloadStringCompleted event client.DownloadStringCompleted += DownloadWebsiteDataCompletedHandler; // Initiate the asynchronous download operation client.DownloadStringAsync(new Uri("https://thedotnetguide.com/privacy-policy/")); Console.WriteLine("Doing some other tasks while waiting data download."); Console.WriteLine("End of the EventBasedAsynPatternDemp program."); } private static void DownloadWebsiteDataCompletedHandler(object sender, DownloadStringCompletedEventArgs e) { if (e.Error != null) { Console.WriteLine("Error occurred: " + e.Error.Message); } else { string result = e.Result; Console.WriteLine("Download Website Page data completed : " + result); } } } } |
In this above example,
- Inside the Main method, we create an instance of WebClient and subscribe to the DownloadStringCompleted event by adding the DownloadWebsiteDataCompletedHandler method as the event handler.
- We initiate the asynchronous download operation by calling DownloadStringAsync and passing the URL as a parameter.
- The DownloadWebsiteDataCompletedHandler method is the event handler that gets executed when the download completes (or encounters an error). It checks if an error occurred, and if so, prints the error message. Otherwise, it retrieves the downloaded string and prints it to the console.
- After initiating the download, the program continues executing and prints “Doing some other tasks while waiting data download” and “End of the EventBasedAsynPatternDemo program.”, which means that the program is not waiting for the download event to complete and instead progresses to next task.
When you run the program, it will print the following output:

Benefits of Asynchronous Programming:
Asynchronous programming comes with following benefits:
- Improved Responsiveness: It allows your program to do multiple tasks simultaneously. This improves the overall responsiveness of your application because it doesn’t block or freeze while waiting for a single task to complete.
- Enhanced Performance: By leveraging asynchronous programming, your application can make better use of system resources, which allows better application performance.
- Better User Experience: It significantly improves the user experience by eliminating unresponsive or frozen interfaces, that allows better user experience.
- Efficient Resource Utilization: Helps optimize the utilization of system resources. By avoiding unnecessary waits and allowing tasks to execute concurrently. It prevents resources from being idle, making your application more efficient and responsive.
Conclusion:
Asynchronous programming in C# lets your program do multiple things at once, making it faster and more efficient. and enhanced user experiences. By utilizing the async and await keywords, developers can tap into the power of concurrency, making their applications more efficient and adaptable.
Thanks for visiting, please go through my other articles on similar topics Tasks in C#