# async and await

In my previous [post](https://sushantpant.com.np/introduction-to-asynchrony), I provided a brief intro to asynchrony. In this post, I will continue with TAP (Task-based Asynchronous Programming) which utilizes TPL (Task parallel library) and it is a standard pattern to achieve asynchrony in modern C#.

## Introduction

In TAP(Task-based Asynchronous Programming), `async` `await` keyword and `Task` class does everything to achieve asynchronous behavior. Simply understanding, the `async` is used to say "this is my asynchronous method/function". But just highlighting a function with `async` keyword doesn't make it asynchronous. If the asynchronous operation which is being awaited by using `await` keyword has not yet completed, it will return immediately. `Task` is a common type that can be awaited. Synchronous flow like not executing next operation is still maintained in asynchronous operation but without blocking or pausing the thread. If the task is already in completed state, code flow will execute as usual.

When long running operation is being awaited, the compiler sets a continuation to be executed after the operation has completed. Meaning, execution will start from where it left after the awaited operation has completed. Continuation is a callback (delegate) that will be executed as soon as the awaited operation has completed. Simpler terms, continuation is just a piece of code to be executed when the awaited operation has completed. Continuations are `Action` delegate that receives result of the asynchronous operation (`Action<Task<TResult>>` or `Action<Task>`). The type of the awaited asynchronous operation is usually `Task` or `Task<TResult>`. You can obviously have your own custom awaitable types but .NET provide `ValueTask<TResult>` which is better than having your own custom type. Custom types for awaiting is not preferred due to potential compatibility and tooling issues.

`Task` has a method called `ContinueWith` to attach continuations. Continuations are heavily used in event-based pattern (EAP). EAP pattern involves the use of events and callback methods to notify the completion of asynchronous task.

TAP (Task-based Asynchronous Programming) doesn't rely heavily on continuations like EAP. TAP uses `await` keyword which provides a way to pause or wait for the asynchronous task to complete without blocking the thread. You might be wondering "what exactly does it mean to block the thread". It means the situation where the execution of code is blocked. It cannot execute further. Basically, the thread where this execution is happening becomes unable to proceed with other tasks.

## Task-based asynchronous pattern

In TAP, asynchronous operation doesn't wait for the task to complete. It starts and returns immediately. But what does it return?. It returns a sort of token. After initiating the asynchronous operation and obtaining the "token" (usually a `Task` or `Task<TResult>`), the execution of the calling code continues immediately. The "token" (`Task` or `Task<TResult>`) is used for coordination. What I mean by that is when you await a task, further execution is paused which allows asynchronous operation to finish before moving on to next step of code. You can await the task, register continuations, or perform any other operations based on the completion status of the asynchronous operation. Here's a simple example to visualize an async method:

```csharp
public async Task<string> PrintSomethingAsync()
{
    Console.WriteLine("Before awaiting.");
    await Task.Delay(2000); // simulating time consuming operation. 
    Console.WriteLine("After awaiting");
    return "returned val from async method.";
}
```

Until the code reaches `await` keyword, it runs synchronously. After that, it starts an asynchronous operation which delays for 2 seconds simulating some computation. After waiting for 2 seconds, it prints and finally returns to the caller.

```csharp
// calling code
string ret = await eg.PrintSomethingAsync();
Console.WriteLine($"Returned from async method: {ret}");
Console.WriteLine("All done.");
```

Output:

```xml
Before awaiting.
After awaiting
Returned from async method: returned val from async method.
All done.
```

When you `await` an asynchronous operation (represented by a `Task` or `Task<TResult>`), it pauses the execution of the method at that point. However, it doesn't block the calling thread. Instead, it allows the calling thread to do other work while waiting for the asynchronous operation to complete. But if the `await` waits for the operation to complete and also immediately returns to the caller, how does it know where to start when the task is completed? This is achieved through the continuation. The compiler generates code to capture the current context and create a continuation that gets executed when the awaited task completes.

## Task

Simply put, `Task` class represents an asynchronous operation. `Task` encapsulates the ongoing or completed asynchronous operation. `Task` class provides varieties of methods to work with asynchronous operation. Some common methods are:

| Method | Description |
| --- | --- |
| `Task.Start` | Starts the task for the execution. |
| `Task.Delay` | Delays the task by passed parameter. |
| `Task.Wait` | Blocks the calling thread until the task completes. |
| `Task.WaitAll` | Wait until all tasks completes. Blocks all the calling thread. |
| `Task.WaitAny` | Wait until any of tasks completes. Blocks all the calling thread until any of the task completes. |
| `Task.ContinueWith` | Attach a continuation to the task. |
| `Task.WhenAll` | Basically saying "do this when all the task has completed". |
| `Task.WhenAny` | Basically saying "do this when any of the task completes". |
| `Task.FromResult` | Creates a task with the completed specified result. |
| `Task.FromCancelled` | Creates a canceled task with the specified cancellation token. |
| `Task.FromException` | Creates a faulted task with the specified exception |
| `Task.IsCanceled` | Gets whether the task has been canceled. |
| `Task.IsFaulted` | Gets whether the task has been faulted. |
| `Task.IsCompleted` | Gets whether the task has been completed. |
| `Task.ConfigureAwait` | Configure how continuations to be scheduled. Basically it is used to specify if you want your execution after continuation to continue in same thread (if `true`) or execute on a ThreadPool thread (if `false`). |
| `Task.Factory` | Access to `Task` class's factory methods. |
| `Task.Status` | Current status of the task. |

`Task` has a `Status` property (`TaskStatus` enum) which holds the current state of the operation. `Task.Status` can be `Running`, `WaitingToRun`, `WaitingForActivation`, `RanToCompletion`, `Faulted`, `WaitingForChildrenToComplete` and `Canceled`.

| Task Status | Meaning |
| --- | --- |
| `Created` : 0 | The `Task` is initiated but not started or asynchronously waiting for completion. |
| `WaitingForActivation` : 1 | The `Task` is created but not yet scheduled for execution. (like: lazy loading of [iterator block](https://sushantpant.com.np/iterators-effortless-sequencing)) |
| `WaitingToRun` : 2 | The `Task` is not executing, but scheduled for execution. |
| `Running` : 3 | The `Task` is currently executing its asynchronous operation. |
| `WaitingForChildrenToComplete` : 4 | The `Task` is completed but waiting for attached task to complete. |
| `RanToCompletion` : 5 | The `Task` is completed without any exceptions. |
| `Canceled` : 6 | The `Task` is canceled before it could complete its operation. (usage of cancellation token) |
| `Faulted` : 7 | The `Task` is completed due to an unhandled exceptions during execution. |

One more thing, `Task` doesn't need to be explicitly disposed. The management of `Task` instances is handled by the runtime and the GC (garbage collector).

When you await a `Task`, the compiler performs an unwrapping operation. This operation handles exceptions if `Task` is faulted, else extracts the result. The result type of the `await` expression is the type of the awaited task's result, which will be `TResult` for `Task<TResult>` or `void` for a plain `Task`. The result is not the original `Task` itself. Example:

```csharp
Task<string> task = SomeHeavyTaskAsync();
string result = await task; // unwraping operation converts Task<string> to string
```

Here, I have a variable called `task` of type `Task<string>`. But when I `await`, it will unwrap from `Task<string>` to `string`.

### Exceptions in Task and why you should await a Task

I previously said that awaiting a `Task` handles exceptions if faulted, else extracts the result. However, what if the task is not awaited? When the `Task` is not awaited, any exceptions that may have occurred during its execution may not be observed immediately. There may be multiple exceptions during this execution period. If not awaited, they will be stored but not thrown. This "stored" exception is called `AggregateException`. `AggregateException` is a wrapper that aggregates multiple exception. The main reason to not throw exception like synchronous flow is to prevent unhandled exceptions causing termination of the application. Also you don't want to hamper other `Task` when there is exception in some `Task` which is executing in parallel. Here is an example to demonstrate it.

```csharp
public async Task<string> DemonstrateExceptionAsync()
{
    await Task.Delay(1000); // simulating some operation
    Console.WriteLine("after some operation.");
    MethodWithExceptionAsync(); // not awaiting
    Console.WriteLine("after exception in other task.");
    throw new Exception(message:"exception inside the method.");
    return "retured from DemonstrateExceptionAsync";
}

public async Task MethodWithExceptionAsync()
{
    await Task.Delay(500); // simulating some operation
    Console.WriteLine("inside MethodWithExceptionAsync method.");
    throw new Exception(message:"Exception outside the method.");
}
```

Here, when `MethodWithExceptionAsync()` is initiated, it won't throw exception. Instead this exception is stored in `AggregateException`. Execution continues and reach another exception which will be stored in `AggregateException` too.

```csharp
// calling code
var exceptionMethod = eg.DemonstrateExceptionAsync();
await Task.Delay(1500);
Console.WriteLine("after initiating method with exception.");
await exceptionMethod;
Console.WriteLine("after awaiting faulted task");
/*
Output:
    after some operation.
    after exception in other task.
    after initiating method with exception.
    inside MethodWithExceptionAsync method.
-- Finally, throws an exception --
System.Exception: 'exception inside the method.'
*/
```

In calling code, I didn't await the anonymous type variable `exceptionMethod` which is assigned to an async method `DemonstrateExceptionAsync()`. All exceptions that occurred within this method is stored in `AggregateException`. Unless I await an async method or if I try to access the result of an async method (`Task.Result`), there won't be any exception. So if I didn't do `await exceptionMethod;`, it won't throw an error.

It's important to understand that using `Task.Result` to get the result of an asynchronous operation can lead to deadlocks. Imagine a scene where you're waiting for a result using `Task.Result`, and the asynchronous operation needs a specific context, like the UI thread. If that context is blocked, a deadlock may occur, which hampers the operation. Output will be the following:

```xml
after some operation.
after exception in other task.
after initiating method with exception.
after awaiting faulted task
```

When I finally await this async method (`await exceptionMethod;`), the most recent exception of `AggregateException` is thrown which is `System.Exception: 'exception inside the method.'`.

Now I'm sure you know why awaiting a task is crucial. You don't want exception to be silent. Also awaiting a task ensures that the code after the `await` statement is executed only after the task has completed. This flow of execution is important to consider in asynchronous programming, preventing race conditions and ensuring expected order of execution.

> [race condition](https://stackoverflow.com/a/34550/13672836): A race condition occurs when two or more threads can access shared data and they try to change it at the same time.

### Cancelling an asynchronous operation

Cancellation in `Task` is supported via `CancellationToken`. This allows an asynchronous operation to cancel its operation. You can think of a real scenario like visiting a website. If that website is taking too long to load, you'll close that tab and reenter the url in new tab or probably reload the page. In such cases(reload, closing tab), browser(client) will send a cancellation token to the server to cancel the operation. This helps in resource utilization.

When an asynchronous operation is cancelled, its state becomes `Canceled`. To use cancellation in `Task`, you can pass `CancellationToken` which will be checked periodically. Example:

```csharp
// asynchronous method which can be cancelled
public async Task DoSomethingWithCancellationAsync(CancellationToken cts)
{
    try
    {
        Console.WriteLine("Inside DoSomethingWithCancellationAsync method.");
        await Task.Delay(5000, cts);
        Console.WriteLine("Still inside DoSomethingWithCancellationAsync method, after long running operation.");
    }
    catch(OperationCanceledException oce)
    {
        Console.WriteLine(oce.Message);
    }
}
```

Here, `Task.Delay` method has a parameter that accepts cancellation token (`cts`) as an argument. This means that if the cancellation token is signaled before the delay completes, the operation will be canceled, and an `OperationCanceledException` will be thrown.

```csharp
// calling code
using (CancellationTokenSource cts = new CancellationTokenSource())
{
    Task someTask = eg.DoSomethingWithCancellationAsync(cts.Token);  // start the task
    try
    {
        await Task.Delay(2000); // delay further execution for 2 seconds
        cts.Cancel(); // cancel the operation after 2 seconds.
        await someTask;        
    }
    catch (OperationCanceledException oce)
    {
        Console.WriteLine($"Operation cancelled: {oce.Message}");
    }
}
/*
Output:
    Inside DoSomethingWithCancellationAsync method.
    A task was canceled.
*/
```

Here, `someTask` has already started the task. `someTask` will take 5 seconds to complete its operation. But I will cancel this operation in 2 seconds.

Now, what if we pass cancellation token after the operation has already completed? Well, cancellation token will have no effect. The asynchronous operation, once completed, cannot be canceled. Example:

```csharp
// calling code
using (CancellationTokenSource cts = new CancellationTokenSource())
{
    Task someTask = eg.DoSomethingWithCancellationAsync(cts.Token);  // start the task
    try
    {
        await Task.Delay(6000); // delay further execution for 6 seconds
        cts.Cancel(); // cancel the operation after 6 seconds.
        await someTask;        
    }
    catch (OperationCanceledException oce)
    {
        Console.WriteLine($"Operation cancelled: {oce.Message}");
    }
}
/*
Output:
    Inside DoSomethingWithCancellationAsync method.
    Still inside DoSomethingWithCancellationAsync method, after long running operation
*/
```

Here, `someTask` has already started the task. `someTask` will take 5 seconds to complete its operation. If I cancel this operation after 6 seconds, it won't cancel `someTask` because it has already completed having its state as `RanToCompletion`.

## Creating an asynchronous method

Asynchronous methods can be generic, static, and can have any access modifiers. Creating an asynchronous method involves using the `async` keyword in the method signature, and the method should return either `Task` for void methods or `Task<TResult>` for methods with a result or `ValueTask<TResult>` or [custom awaitable types.](https://devblogs.microsoft.com/pfxteam/await-anything/) Parameters for async methods are similar to regular methods, but `ref` and `out` are disallowed.

`ref` and `out` are disallowed due to the complications of managing the state of these parameters across various asynchronous operation. Imagine a scenario where some async method is computing progress value (percentage). If `ref` and `out` were allowed, it would really be complex to work around. What if some referenced variable's value is modified in race condition?

### Asynchronous anonymous function

Async [anonymous function](https://sushantpant.com.np/captured-variables-lambda-expression-and-closures#heading-lambda-expression) are just unnamed lambda expression but are asynchronous. It allows for concise representation of asynchronous operations without the need to define a named method. To declare it, you use the `async` keyword just before a lambda expression.

Asynchronous lambda expression syntax: `async (parameter-list) => (expression-body)`

This results in a concise way to represent a function with asynchronous operations. Example:

```csharp
public async Task DoSomethingWithAnonFuncAsync()
{
    Func<Task<string>, Task<int>> getStringLengthDelegateAsync = async (str) =>
    {
        string task = await str;  // await parameter which is of type task
        return task.Length;
    };
    async Task<string> someStringLocalFuncAsync() // local function can be asynchronous as well
    {
        await Task.Delay(2000); // simulating some operation
        return "something";
    }
    Task<int> getLengthTask = getStringLengthDelegateAsync(someStringLocalFuncAsync());
    int len = await getLengthTask; // unwrapping operation by await. Task<int> --> int
    Console.WriteLine($"Length of string is: {len}");
}
```

This code might look a lot but let me break it down. Firstly, I created a delegate of type `Func<Task<string>, Task<int>>`. For implementation of this delegate, I created an anonymous async function which returns the length of the string passed(`str`). I awaited the passed string of `getStringLengthDelegateAsync` because it is asynchronous of `Task` type. `await` unwraps the result of `Task<string>` to `string`. Then return the length of that string. After that, you can see I created a local async function. Yes, local function can be asynchronous too. This local function named `someStringLocalFuncAsync` returns `Task<string>` after a 2 seconds delay.

Next, I created a variable of type `Task<int>` and assign it to the delegate. I passed a local function as an argument for this delegate because you can see that the return type of the local function `someStringLocalFuncAsync` and the parameter for the delegate `Func<Task<string>, Task<int>> getStringLengthDelegateAsync` are the same, i.e., `Task<string>`. After this, I await the `Task<int>` which unwraps the result as `int` and assign that to a integer variable. Finally, print that `int`.

```csharp
// calling code
await eg.DoSomethingWithAnonFuncAsync();
/*
Output:
    Length of string is: 9
*/
```

### Success or failure of async execution

Awaited asynchronous have two possibilities. Either it has completed without any exception (`RanToCompletion`) or it has failed due to some exception (`Faulted`). When an async method waits for an asynchronous operation to complete, it really means the method is doing nothing. A continuation is attached to the operation and the method returns immediately. `SynchronizationContext` makes sure that the continuation executes in the right thread in GUI application.

> [From stackoverflow:](https://stackoverflow.com/a/18098557/13672836) Simply put, [`SynchronizationContext`](http://msdn.microsoft.com/en-us/library/system.threading.synchronizationcontext.aspx) represents a location "where" code might be executed. Delegates that are passed to its [`Send`](http://msdn.microsoft.com/en-us/library/system.threading.synchronizationcontext.send.aspx) or [`Post` method](http://msdn.microsoft.com/en-us/library/system.threading.synchronizationcontext.post.aspx) will then be invoked in that location. (`Post` is the non-blocking / asynchronous version of `Send`)

In Asp.Net Core, there is no dedicated UI thread. It makes sense to eliminate the dedicated UI thread in web APIs and web server scenarios. Asp.Net Core utilizes (TAP) task-based asynchronous pattern's async-await pattern to achieve asynchrony. Console application and background services utilizes thread pool. When an asynchronous operation completes in console app or background services, the continuation may run on a different thread from the one that initiated the operation. The thread pool efficiently manages these threads, preventing the application from being blocked.

| Thread pool | UI thread |
| --- | --- |
| Manage and provide workers threads. | Manage user interface in GUI applications. |
| Avoids the overhead of creating and destroying threads for each asynchronous operation. | Important for updating UI elements, handling user interactions, and maintaining a smooth user experience. |
| Threads from the pool are reused, leading to improved performance and resource utilization. | `SynchronizationContext` ensures that asynchronous continuations execute in the correct UI thread context. |

## `await` does it all

When you `await` an asynchronous operation, the compiler pause the further execution until the operation completes. The compiler generates continuation to execute as soon as the operation completes and returns. If the awaited operation has not completed, it will return immediately. The calling code can continue with its execution, ensuring non-blocking behavior. If the environment is GUI, there is a `SynchronizationContext` which ensures that the continuation runs on the same UI thread. In context of Asp.Net core, where UI thread is not needed, continuations may run on a different thread (from ThreadPool).

If the awaited task completes with an exception, `await` handles it. If the task is faulted, it throws an exception. If it's canceled, it throws an `OperationCanceledException`. If the task completes successfully, it continues with the next line of code.

### What can be awaited

Any type that has a suitable methods or extension method can be awaited. Most common type that can be awaited is `Task`, `Task<TResult>`, `ValueTask<TResult>`, `IAsyncEnumerable<T>`, or any custom type which fulfills Task-Based Asynchronous Pattern can be awaited. Awaitable type must implement `System.Runtime.CompilerServices.INotifyCompletion` interface.

If we look at `Task<TResult>`, C# compiler looks for the following detail to be awaitable:

1. `GetAwaiter` method: The `Task<TResult>` type should have a parameterless method named `GetAwaiter` that only returns an awaiter object and cannot be void. For eg: `Task<string>` has such method like: `public TaskAwaiter<string> GetAwaiter();`. The return type of `GetAwaiter` method is called the awaiter type.
    
2. Awaitable types must implement `System.Runtime.CompilerServices.INotifyCompletion` interface. For eg: The `Task<string>` has such struct as `public struct TaskAwaiter<string> : INotifyCompletion`.
    
3. This awaiter type must have following property and method, respectfully:
    
    * `bool IsCompleted`
        
    * `void OnCompleted(Action<TResult>)`
        
4. `IsCompleted` indicates whether the asynchronous operation has completed or not.
    
5. `OnCompleted` receives `Action<TResult>` that will be executed once the awaited operation finishes or once `IsCompleted` is `true`.
    
6. Awaitable type must have `GetResult` method. `GetResult` is a non-generic parameterless method of the awaiter type (e.g., `TaskAwaiter<TResult>`). It retrieves the result of the awaited asynchronous operation. It is called when `IsCompleted` is `true`. Eg: `public TResult GetResult(){ ... }` for `TResult` or `public void GetResult()` for `Task` or `void`.
    
7. `GetResult` method is also responsible for handling the result of the asynchronous operation. When the asynchronous operation has an exception, it will throw that exception to the caller. This is to make sure that any exceptions that occurred during the asynchronous operation are appropriately shown to the point where the asynchronous operation was awaited.
    

## Full codebase goes into async mode

When there is an async method which has an asynchronous operation calling another async method and every operation is awaited, this creates a chain of asynchronous operations which ensures that the application remains responsive and efficient, handling tasks without blocking threads. Or in other word "the full codebase goes in async mode". That's how you achieve asynchrony.

```csharp
public async Task A()
{
    await B();
}

private async Task B()
{
    await C();
}

private async Task C()
{
    await D();
}

private async Task D()
{
    await E();
}

private async Task E()
{
    await F();
}

private async Task F()
{
    await Task.Delay(1000);
}
```

Here, you can see a chain of asynchronous tasks where each task awaits the completion of the next one.

```csharp
// calling code
var someAsyncCodeTask = asyncMode.A();
await someAsyncCodeTask;
Console.WriteLine($"All async mode task completed. Status: {someAsyncCodeTask.Status}");
/*
Output:
    All async mode task completed. Status: RanToCompletion
*/
```

Here, call to `A` method would initiate a chain of an asynchronous operation. `A` is like the entry point. When you call `A`, it kicks off a sequence of tasks. `A` immediately says, "I'm going to wait for `B` to finish before I'm done." `B` is the second task. When `A` is waiting for `B`, it's like putting `B` on the to-do list and moving on to other things. `B` also says, "I'm going to wait for `C` to finish." `C` joins the chain. `A` is waiting for `B`, and `B` is waiting for `C`. `C` says, "I'll wait for `D` to finish." Same goes for Task `D` and `E`.

Finally, `F` is the last in line. `A`, `B`, `C`, `D`, and `E` are all waiting for `F`.

In summary, transitioning your codebase into async mode not only improves the efficiency and responsiveness of your application but also sets the foundation for scalable and performant software, especially in scenarios where parallel execution of tasks can significantly enhance overall system.

## Summary

1. TAP uses `async` `await` keyword and the `Task` class to achieve asynchrony.
    
2. `Task` class represents an asynchronous operations.
    
3. Async methods don't wait for completion; they start and return immediately.
    
4. Awaiting tasks handles exceptions immediately.
    
5. Avoid using `Task.Result` to prevent deadlocks.
    
6. `CancellationToken` allows canceling asynchronous operations.
    
7. `SynchronizationContext` manages the execution context, mostly in GUI applications where there is UI thread.
    
8. Asp.Net Core utilizes TAP to achieve asynchrony without a dedicated UI thread.
    
9. Async methods can be generic, static, and can have various access modifiers.
    
10. `ref` and `out` parameters are disallowed for simplicity in state management.
    
11. Awaiting tasks can result in completion (`RanToCompletion`) or failure (`Faulted`).
    
12. Proper awaiting ensures expected execution order and prevents race conditions.
    
13. Common awaitable types include `Task`, `Task<TResult>`, `ValueTask`, and `IAsyncEnumerable`.
    
14. Any type with suitable methods or extension methods can be awaited.
    
15. Chaining async methods (asynchronous programming) creates a responsive and efficient application.
    

[Sourcecode](https://github.com/sushantpt/async_await_demo)

More on async await can be read at:

* [C# in depth](https://csharpindepth.com/) Fourth edition by Jon Skeet
    
* [David Fowler's tips on best asynchronous programming practices](https://github.com/davidfowl/AspNetCoreDiagnosticScenarios/blob/master/AsyncGuidance.md)
    
* [NDC conference: Efficient Async and Await](https://www.youtube.com/watch?v=n6kiJKr4_oA) by Filip Ekberg
