C# Asynchronous

Introduction
Hello all, today I back with another C# topic, and today I will share what i learned about C# Asynchronous. I hope with this article you will know more about C# Asynchronous and use it on your project.
What Is It?
Microsoft introduced asynchronous programming in .NET Framework 4.0 to improve the handling of long-running tasks, such as file I/O, network communication, or database operations, without blocking the main thread.
In traditional synchronous programming, operations are executed in a sequential order, meaning one operation must complete before the next one can begin. In contrast, asynchronous programming allows other tasks to run concurrently while waiting for a long-running operation to finish.
Why Implement It?
There are several pros and cons to consider before implement asynchronous in our project. Here are some of them:
Pros
Enhances application responsiveness during long-running operations.
Increases application scalability by allowing concurrent task handling.
Optimizes resource usage by freeing up threads while waiting for tasks.
Cons
May introduce deadlocks if not managed carefully.
Can lead to unexpected behavior due to context switching.
Can make debugging more challenging because of non-linear execution.
How It Works?
To understand how asynchronous work in the system, let's implement it first. In C#, a basic asynchronous operation requires three key components: async, Task, and await.
Async
This modifier is applied to methods to indicate they contain asynchronous operations and allows the method to use the await keyword.
Await
This keyword is used before calling an asynchronous method. It tells the compiler to pause the execution of the current method until the awaited task completes. Importantly, it doesn’t block the thread and lets the program continue executing other tasks while waiting for the asynchronous operation to finish.
Task Or Task<T>
These keywords represent an asynchronous operation.
Taskis used when the operation doesn’t return a value, andTask<T>is used when the operation returns a value of typeTasynchronously.
using System;
using System.Threading.Tasks;
namespace Lncodes.Example.Async;
public sealed class Program
{
static async Task Main(string[] args)
{
await LoadAssetAsync();
}
private async Task LoadAssetAsync()
{
await Task.Delay(2000);
Console.WriteLine($"Asset loaded.");
}
}
In the code above, I have created an asynchronous method that will await 2 seconds before print "Asset loaded." on the console. After implementing an asynchronous method in the code, here's what will happen in the system:
When an asynchronous method is called, it doesn't automatically run on a separate thread. Instead, it begins executing synchronously until it reaches the first
awaitkeyword.When the
awaitkeyword is encountered, the method is divided into two parts. The code beforeawaitruns immediately, while the code afterawaitis delayed and executes later as a continuation (or callback) once the awaited operation completes (e.g.,await Task.Delay(2000)).When the operation of
awaitis running, the system will handle the threading differently. If the operation is I/O-bound (e.g., database query, file reading, or web request), the operation is sent to the OS kernel to allow it to communicate with the hardware (e.g., network card or disk controller). However, if the operation is CPU-bound (e.g., heavy calculations), it will be sent to another thread in the thread pool.Once the awaited operation completes, the Task Scheduler ensures the continuation executes in the correct context. If a
SynchronizationContextis present (such as in a UI or ASP.NET application), it ensures the continuation is synchronized and runs in the appropriate context (e.g., back on the main thread) to prevent race conditions.
Console Application
In my console application, I use an asynchronous approach to create a game asset loader. This implementation ensures that assets like textures and audio files load without blocking the main thread. It also includes a cancellation feature, allowing the loading process to be stopped when necessary.
Below is a list of the classes I used to create this console application, along with a brief explanation of each class:
| Class | Description |
| GameAssetLoader | This class is responsible for asynchronously loading game assets such as textures and audio files. |
| Program | This class is used to execute the game asset loading process asynchronously. |
In the video above, the console application displays the asynchronous loading process of game assets, including textures and audio files, and shows how the process can be canceled midway.
Additional Information
I have discovered some additional information about C# Asynchronous. If you have any additional information regarding C# Asynchronous that you'd like to share, please feel free to leave a comment.
Naming Guidelines
When implementing asynchronous, following specific naming guidelines can help ensure code readability and consistency. Here are some naming conventions recommended by Microsoft:
- Do use 'Async' suffix for asynchronous method e.g.
TimerAsync,PushDataAsync, etc.
Further Discoveries
Here are some further discoveries I have gathered from various sources that may provide a deeper understanding of C# Asynchronous:
Avoid using
.Resultor.Wait()to get results from aTask, as they can cause deadlocks. A better approach is to useawait, which allows asynchronous code to run without blocking the current thread. Deadlocks are particularly problematic in UI applications and other scenarios where maintaining thread responsiveness is essential.The
ConfigureAwait(false)method can be used to improve the performance of asynchronous operations by preventing the continuation from capturing the original synchronization context. However, be cautious, as it may cause issues if your code depends on running on a specific thread, such as when updating the UI in desktop applications.Avoid using
async void, as it can lead to race conditions by allowing the calling code to continue without waiting for the asynchronous method to finish. Useasync voidonly in cases where awaiting the method’s completion is unnecessary. In all other situations, prefer returning aTaskorTask<T>to handle asynchronous operations more effectively.Before .NET 4.5,
Task.Factory.StartNew()was commonly used to create and start tasks with flexible configurations. However, starting with .NET 4.5,Task.Run()became the preferred option for simpler task creation and execution, as it runs tasks on theThreadPoolby default without needing additional configuration, unlikeTask.Factory.StartNew().A
CancellationTokenis used to signal and manage cancellation requests in asynchronous operations, allowing them to be interrupted or stopped before they complete.A
ValueTaskcan be used instead of aTaskin asynchronous methods where the operation might complete synchronously or when the result can be produced without needing to await any operations.




