Exploring Asynchronous Execution and Concurrent Tasks in C# (Async & Await)

Mohamed Hendawy
3 min readJul 15, 2023

--

Asynchronous programming is a powerful technique in C# that allows for efficient execution of operations that may take time to complete, such as I/O operations or long-running tasks. By leveraging asynchronous execution, we can ensure that the program remains responsive and efficient, making the most out of system resources. In this article, we’ll explore the concept of asynchronous execution in C# and demonstrate an example where other tasks are performed concurrently during a download operation.

Understanding Asynchronous Execution: In synchronous programming, each operation blocks the program execution until it completes, which can lead to performance bottlenecks, especially when dealing with time-consuming operations. Asynchronous programming, on the other hand, enables non-blocking execution. By utilizing the async and await keywords in C#, we can designate certain operations as asynchronous, allowing the program to continue executing other tasks while waiting for the asynchronous operation to complete.

Concurrent Task Example: Let’s consider an example where we want to download content from a remote server while simultaneously performing other tasks in the program. We’ll simulate the download operation using the HttpClient class and demonstrate the use of concurrent tasks using asynchronous execution. Here's the code example:

using System;
using System.Diagnostics;
using System.Net.Http;
using System.Threading.Tasks;

public class Program
{
public static async Task Main()
{
Console.WriteLine("Starting the program.");

// Start the download and other tasks concurrently
Stopwatch stopwatch = Stopwatch.StartNew();
Task<string> downloadTask = DownloadContentAsync();
OtherTask();

// Wait for the download task to complete
string content = await downloadTask;
stopwatch.Stop();

Console.WriteLine($"Downloaded content length: {content.Length}");
Console.WriteLine($"Total execution time: {stopwatch.ElapsedMilliseconds} ms");

Console.WriteLine("Program completed.");
Console.ReadLine();
}

public static async Task<string> DownloadContentAsync()
{
Console.WriteLine("Downloading content asynchronously...");

using (HttpClient client = new HttpClient())
{
string response = await client.GetStringAsync("https://www.example.com");

Console.WriteLine("Content downloaded asynchronously.");
return response;
}
}

public static void OtherTask()
{
Console.WriteLine("Performing other task...");
// Simulate some time-consuming task
Task.Delay(2000).Wait();
Console.WriteLine("Other task completed.");
}
}

In this example, the Main method initiates two concurrent tasks: the download task (DownloadContentAsync) and the other task (OtherTask). The main thread doesn't block while waiting for the download to complete.

The OtherTask method simulates a time-consuming task by using Task.Delay to introduce a delay of 2 seconds. During this delay, the main thread can proceed with other work.

After starting the download and initiating the other task concurrently, the program awaits the completion of the download task using await downloadTask. This ensures that the program doesn't proceed further until the download is finished.

When the download task completes, the downloaded content length is displayed, along with the total execution time of the program, which includes the time taken by both the download and the other task.

This example demonstrates how asynchronous execution allows the program to perform other tasks concurrently with the download operation, making the program more efficient and responsive by utilizing the main thread for additional work.

Output :

Benefits of Concurrent Task Execution: By utilizing asynchronous execution and concurrent tasks, we gain several benefits:

  1. Responsiveness: The program remains responsive and doesn’t block the main thread while waiting for the download operation. This ensures a smooth user experience, especially in applications with graphical user interfaces.
  2. Efficiency: While waiting for the download to complete, the main thread can be utilized for performing other tasks, such as processing data, handling user input, or making additional API calls. This improves the overall efficiency of the program.
  3. Utilization of Resources: By performing tasks concurrently, we can leverage the available system resources effectively. Multiple tasks can be executed in parallel, utilizing CPU cores or performing I/O operations efficiently.

Conclusion: Asynchronous execution and concurrent task execution are powerful techniques in C# that enable efficient and responsive programs. By leveraging the async and await keywords, we can design applications that make the most out of system resources, improve responsiveness, and handle time-consuming operations effectively. Incorporating asynchronous execution and concurrent tasks in your programs can lead to more efficient and scalable solutions.

References:

--

--