Asynchronous C#: Cherry on the top 🍒 (Tips and Tricks)
Tags: csharp, webdev, dotnet
Published: 2021-05-22 06:20:28

In [Part 1](https://dev.to/paulafahmy/asynchronous-c-making-a-simple-cup-of-tea-13i) and [Part 2](https://dev.to/paulafahmy/asynchronous-c-making-a-simple-cup-of-tea-part-2-1jcj) of the series, we took a nice dive to get us started in writing efficient async code in C#, I wanted to finalize the series with a couple of Tips and Tricks that will certainly come in handy in most development cases.

Buckle up your seatbelts 🚀..

### ✔ Tip #1
```csharp
static async Task BoilWaterAsync()
{
    Console.WriteLine("Starting the kettle");
    await Task.Delay(3000);
    Console.WriteLine("Kettle Finished Boiling");
}

static async Task PourWaterAsync()
{
    var boilWaterTask = BoilWaterAsync();
    await boilWaterTask;
    Console.WriteLine("Pouring boiling water.");
}

static async Task Main(string[] args)
{
    // Notice we are not awaiting the task!
    PourWaterAsync();
    Console.WriteLine("Program Ended");
}

```
In our first example, `PourWaterAsync()` represents a `Task` that is not awaited, although, the task consists of inner tasks that are indeed being awaited.

Running this example will result in the following output:
```
Starting the kettle
Program Ended
```
The task `Task.Delay(3000)` has started, but despite awaiting it, it did not get to reach the finishing line, and the kettle did not finish boiling.
This behavior has resulted due to skipping the `await` keyword in the top-level `Main()` function.

Of course, rewriting these two lines:
```csharp
var boilWaterTask = BoilWaterAsync();
await boilWaterTask;
```
to be:
```csharp
await BoilWaterAsync();
```
.. would give the same result.
Always remember to "await" any task till reaching the very last calling point.

### ✔ Tip #2
```csharp
public void Main(string[]args)
{
    var task = BoilWaterAsync();

    // DON'T
    var result = task.Result;

    // A NO-NO
    task.Wait();

    // PLEASE DON'T ⛔
    task.GetAwaiter().GetResult();
}


```

The above three **DON'Ts** will cause the application's main thread to be blocked till the tasks are finished, the app might stop responding or processing new requests till the synchronous wait is completed.

**✅ DO:**
Embrace the asynchronous nature of the task, await it, and return the result. Tasks being propagated throughout your code **is normal**, just try to delay doing so as much as you can.


### ✔ Tip #3
Let's say we are implementing an interface, one of its methods requires a Task<string> to be returned, **BUT** the execution of the method itself does not require an asynchronous setup, it would not block the main thread and can run synchronously without problems.

```csharp
interface MyInterface
{
    Task<string> DoSomethingAndReturnAString();
}

class MyClass : MyInterface
{
    public Task<string> DoSomethingAndReturnAString()
    {
        // Some logic that does not need the await keyword
        return "result"; // Of course a compiler error, expecting Task<string> not a string
    }
}
```
We can solve this issue with two approaches:
#### Solution 1 (a bad one 👎):
Convert the method to be **`async`** **(even though we do not need to await anything)**, and now we could return a string normally, right? **DON'T ever do that!**

The moment you mark a method as **`async`**, the compiler transforms your code into a **state machine** that keeps track of things like yielding execution when an await is reached and resuming execution when a background job has finished. In fact, if you checked the IL *(Intermediate Language)* generated from your code after marking a method as **`async`**, you'll notice that the function has turned into an entire class for that matter.

So even on synchronous method marked with async (without await inside), a state machine will still be generated anyways and the code which could potentially be inlined and executed much faster will be generating additional complexity for state machine management.

📝 **That's why it's so important to mark methods as async if and only if there is await inside.**

#### Solution 2 (much better 👍):
Instead: `return Task.FromResult("result");`

Let's take another example:

We have an HTTP client retrieving some text from an external web source,
```csharp
public Task<string> GetFromWebsite()
{
    var client = new HttpClient();
    var content = client.GetStringAsync("my.website.com");
    
    •••
}
```
If the objective is to only start retrieving the string from the website, then the best way to do it is to return the task of `GetStringAsync()` as is, and **do not await it here**, it boils down to the same reason of skipping the aimless creation of a state machine.

```csharp
public Task<string> GetFromWebsite()
{
    var client = new HttpClient();
    return client.GetStringAsync("my.website.com");
}
```

The only case you'd want to await the call is that you want to perform some logic on the result **inside** the method:

```csharp
// Notice that we marked the method as async
public async Task<string> GetFromWebsiteAndValidate()
{
    var client = new HttpClient();
    var result = await client.GetStringAsync("my.website.com");
    
    // Perform some logic on the result
    
    return result;
}
```
Remember, if you used the word "and" while describing what a method does, something might not be right.
Example: 
- "My method is doing *x* and *y* and *z*" (NO-NO ⛔)
- "I have 3 methods, one for doing *x*, another for *y*, and the last for *z*" (YES ✔)

This will make your life much easier when trying to apply unit tests to your code.

So a rule of thumbs 👍 to note down here:
Only **await** when you **absolutely need** the result of the task.
The async keyword does not run the method on a different thread, or do any other kind of hidden magic, hence, only mark a method as **async** when you need to use the keyword **await** in it.

A couple of notes to always remember:
- An **async** function can return either on of the three types: `void`, `Task`, or `Task<T>`.
- A function is "awaitable" because it returns a `Task` or a `Task<T>`, not because it is marked `async`, so we can `await` a function that **is not async** (a one just returning `Task`).
- You cannot `await` a function returning `void`, hence, you should always return a `Task` unless there is an absolute reason not to do so (a caller to the function expects a void return type), or that the function itself is a top-level function and there is no way other functions will be able to call it..

### ✔ Tip #4
We established that long-running tasks should always execute asynchronously, these tasks can fall down into two main categories, **I/O-Bound** and **CPU-Bound**. A task is said to be I/O bound when the time taken for it to complete is determined principally by the period spent waiting for input/output operations to be completed. In contrast, a CPU-Bound task is a task that's time of completion is determined principally by the speed of the central processor, examples for these would be:
- I/O Bound Tasks:
    - Requesting data from the network
    - Accessing the database
    - Reading/Writing to a file system
- CPU Bound Tasks: Generally performing an expensive calculation such as:
    - Graphics Rendering
    - Video Compression
    - Heavy mathematical computations
    
Generally, whenever you got an I/O Bound `Task` or `Task<T>` at hands, `await` it in an `async` method. For CPU-bound code, you await an operation that is started on a background thread with the **[`Task.Run`](https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.run)** method. 

**Note 📝:**
Make sure you analyzed the execution of your CPU-Bound code, and be mindful of the context switching overhead when multithreading, it might be not so costly after all in comparison.

Okay, that's all I have for y'all today.
Keep Coding 😉