Async and Await in C# with Examples

In C#, async and await are language features used to write asynchronous code that can execute concurrently without blocking the main thread. async is used to define an asynchronous method, while await is used to asynchronously wait for the completion of an operation. Asynchronous programming can improve the performance and responsiveness of your applications, especially in scenarios where I/O operations are involved.

What is Synchronous programming?

Synchronous programming is a programming model in which each statement in a program is executed one after another in a sequential order. In other words, when a method is called in a synchronous program, the program waits for the method to complete before executing the next statement.

Synchronous programming is straightforward to understand and debug because the program executes each statement in order. However, this can lead to performance issues when executing long-running or I/O-bound operations. In synchronous programming, if an operation takes a long time to complete, the program will be blocked until the operation finishes. This can make the program appear unresponsive to the user.

For example, consider the following code snippet in C#:

public void DoTask() { Step1(); Step2(); Step3(); }

In the above example, Step1() is executed first, followed by Step2() and Step3(). The program waits for each method to complete before executing the next one.

Synchronous programming can be useful for small applications or simple algorithms that don't require a lot of concurrency or parallelism. However, in larger or more complex applications, asynchronous programming is often used to improve performance and responsiveness.

What is Asynchronous programming?

Asynchronous programming is a programming model in which multiple tasks or operations are executed concurrently, without blocking the main thread. In other words, asynchronous programming allows you to perform multiple operations simultaneously, without waiting for each operation to complete before starting the next one.

In asynchronous programming, a method can start an operation and then return immediately, allowing other operations to be executed while the first operation is running. When the first operation completes, the method can continue execution or notify the caller that the operation has finished.

Asynchronous programming is especially useful for long-running or I/O-bound operations, such as database queries, network requests, or file I/O. By executing these operations asynchronously, the program can continue running other tasks while waiting for the I/O operations to complete, improving the overall performance and responsiveness of the program.

For example, consider the following code snippet in C# using the async/await keywords:

public async Task DoTaskAsync() { await Step1Async(); await Step2Async(); await Step3Async(); }

In the above example, each method is marked as asynchronous using the async keyword, and each operation is awaited using the await keyword. This allows each operation to execute concurrently and asynchronously, without blocking the main thread.

Asynchronous programming can be more complex than synchronous programming, and requires careful management of synchronization and error handling. However, it can greatly improve the performance and responsiveness of your applications, especially in scenarios where I/O operations are involved.

async await in C#

Following are some important points to keep in mind when using async and await in C#:

  1. The async and await are keywords used to write asynchronous code in C#. They allow you to perform time-consuming operations without blocking the main thread.
  2. The async keyword is used to mark a method as asynchronous. When a method is marked as async, it can contain one or more await expressions, which indicate points where the method can be suspended and resumed.
  3. When a method contains an await expression, the method returns a Task or Task object. This object represents the asynchronous operation that the method performs.
  4. The await keyword is used to asynchronously wait for the completion of an operation that returns a Task or Task object. When the operation is complete, the method resumes execution.
  5. Asynchronous methods should be named with an "Async" suffix to indicate that they are asynchronous. For example, CalculateAsync, LoadDataAsync, etc.
  6. Asynchronous methods should return a Task or Task object, depending on whether they return a value or not. If a method doesn't return a value, it should return Task instead of void.
  7. Asynchronous methods can improve the performance of your application, but they can also increase complexity. Be sure to carefully manage synchronization and error handling to avoid bugs and race conditions.
  8. Asynchronous methods can be used in combination with the Task and Task classes to perform parallel operations, handle exceptions, and more.

By following these best practices and using async and await correctly, you can write more efficient and responsive code in C#.

A realtime example of using async and await

Following an example of using async and await to improve the responsiveness of a Windows Forms application that performs a long-running task.

Suppose you have a Windows Forms application with a button that starts a long-running task when clicked. Before using async and await, the code for the button click event might look something like this:

private void btnStart_Click(object sender, EventArgs e) { // Disable the button to prevent multiple clicks btnStart.Enabled = false; // Perform a long-running task DoLongRunningTask(); // Re-enable the button when the task is complete btnStart.Enabled = true; }

In the above example, the DoLongRunningTask() method performs a long-running task that might take several seconds or more to complete. Because the method runs synchronously on the UI thread, the application becomes unresponsive during the task, and the user cannot interact with it.

To make the application more responsive, you can use async and await to run the long-running task asynchronously on a separate thread, like this:

private async void btnStart_Click(object sender, EventArgs e) { // Disable the button to prevent multiple clicks btnStart.Enabled = false; // Perform a long-running task asynchronously await Task.Run(() => DoLongRunningTask()); // Re-enable the button when the task is complete btnStart.Enabled = true; }

In the above updated code, the DoLongRunningTask() method is executed asynchronously using the Task.Run method, which creates a new Task object that runs the method on a separate thread. The await keyword is used to suspend the execution of the btnStart_Click method until the Task object is complete, allowing the UI thread to remain responsive during the task.

By using async and await in this way, you can improve the responsiveness of your Windows Forms application and provide a better user experience.

Other methods used in combination with async/await


how to study async and await in C#

In C#, there are several methods and keywords that can be used in combination with async/await to create asynchronous code, including:

  1. Task: Represents an asynchronous operation that can be waited on and cancelled.
  2. Task: Represents an asynchronous operation that returns a value of type T.
  3. async: Keyword used to define an asynchronous method.
  4. await: Keyword used to asynchronously wait for the completion of an operation.
  5. Task.Run: Method used to execute a method or delegate asynchronously on a thread from the thread pool.
  6. Task.WhenAll: Method used to asynchronously wait for the completion of multiple tasks.
  7. Task.WhenAny: Method used to asynchronously wait for the completion of any of multiple tasks.
  8. async void: Used to define an asynchronous method that doesn't return a value.
  9. ConfigureAwait: Method used to configure the context in which the continuation of an asynchronous method executes.
  10. async Task: Used to define an asynchronous method that returns a Task object.
  11. async Task: Used to define an asynchronous method that returns a Task object.
  12. CancellationToken: A structure used to signal cancellation to cooperative cancellation points.
  13. CancellationTokenSource: A class used to generate cancellation tokens.
  14. IProgress: A generic interface used to report progress updates from an asynchronous operation to a UI element.

These methods and keywords can be used in various combinations to create efficient and scalable asynchronous code in C#.

How and when to use 'async' and 'await' in C#

In C#, async and await are used to write asynchronous code that can execute concurrently, without blocking the main thread. Here are some guidelines on how and when to use async and await:

  1. Use async when the method involves I/O-bound or CPU-bound work that takes a significant amount of time to complete, such as network requests, file I/O, or database queries.
  2. Use await to asynchronously wait for the completion of an operation. When an await expression is encountered, the method is suspended until the operation completes. This allows other operations to be executed concurrently, improving the overall performance and responsiveness of the program.
  3. Use async and await together to write an asynchronous method that returns a Task or Task object. The Task object represents the asynchronous operation that the method performs. If the method doesn't return a value, it returns Task instead of void.
  4. Use Task.Run to execute a method or delegate asynchronously on a thread from the thread pool. This can be useful for CPU-bound work that would otherwise block the main thread.
  5. Use Task.WhenAll to asynchronously wait for the completion of multiple tasks. This method returns a Task object that completes when all of the input tasks have completed.
  6. Use Task.WhenAny to asynchronously wait for the completion of any of multiple tasks. This method returns a Task object that completes when any of the input tasks have completed.
  7. Use CancellationToken and CancellationTokenSource to allow for cooperative cancellation of asynchronous operations. This can be useful in scenarios where a user wants to cancel an operation before it completes.

Conclusion:

Async and await are powerful tools for writing efficient and scalable asynchronous code in C#. By using them wisely, you can improve the performance and responsiveness of your applications, especially in scenarios where I/O operations are involved.