Miscellaneous C# Async Tips
Tags: csharp
Published: 2019-03-10 12:57:13

---
title: Miscellaneous C# Async Tips
published: true
tags: csharp
canonical_url: https://stu.dev/miscellaneous-csharp-async-tips/
---

There are lots of great async tips out there, here a random few that I've collected over the past couple of years that I haven't seen much written about.

### Use Discards with `Task.Run` for Fire and Forget

This is a minor bit of guidance, but one of my favourites. If you are starting a `Task` in a fire-and-forget manner with `Task.Run`, other readers of the code might be thinking "did they forget to `await` the returned task here?".

You could make your intent explicit with a comment, but a very concise and clear way to indicate this was your intention is to use [the discard feature in C# 7.0](https://docs.microsoft.com/en-us/dotnet/csharp/discards):

```csharp
Task.Run(() => SomeBackgroundWork()); // Fire and forget

// becomes

_ = Task.Run(() => SomeBackgroundWork());
```

Of course, comment if you need to clarify anything, but in this example, I think it makes sense to omit the comment as it leaves less noise.

## Replace `Task.Factory.StartNew`

`Task.Factory.StartNew` was often used before `Task.Run` was a thing, and `StartNew` can be a bit misleading when you are dealing with async code as it represents the initial _synchronous_ part of an async delegate, due to their being no overload that takes a `Func<Task<T>>`.

Stephen Cleary even [goes as far to say it is dangerous](https://blog.stephencleary.com/2013/08/startnew-is-dangerous.html), and has very few valid use cases, including being able to start a `LongRunning` task for work that will block in order to prevent blocking on your precious thread pool threads. Bar Arnon [points out this almost never mixes well with async code](http://blog.i3arnon.com/2015/07/02/task-run-long-running/). In short `StartNew` is rarely useful, and importantly could cause confusion.

My first tip is, where ever you see the following:

```csharp
Task.Factory.StartNew(/* Something */).Unwrap()
```

to make it more familiar to other readers of the code, you can replace it with:

```csharp
Task.Run(/* Something */)
```

If you see usages without `Unwrap()`, there's a chance it's not doing what you think it's doing. Or if you are using it to start a task with custom `TaskCreationOptions`, be sure it's required for your scenario. To be clear, here is a rare scenario where it would make sense:

```csharp
Task.Factory.StartNew(() =>
{
    while (true)
    {
        Thread.Sleep(1000); // Some blocking work you wouldn't want happening on your threadpool threads.
        DoSomething();
    }
}, TaskCreationOptions.LongRunning);
```

### Async & Lazy

One common place where people get caught out in migrating synchronous code to async is where they have lazy initiated properties or singletons, and it now needs to be initialized asynchronously. A great tool in your toolbelt in the sync world to deal with this is `Lazy<T>`, however, how can we use this with async and Tasks?

By default `Lazy<T>` uses the setting `LazyThreadSafetyMode.ExecutionAndPublication`, this means it's thread-safe, and if multiple concurrent threads try to access the value, only one triggers the creation, and the others all wait for the value to become available.

What's nice is this is kind of how `Task<T>` works with regards to awaiting. If one thread creates a `Task` instance that is awaited by other threads before it completes, they wait for the value to become available, without additionally executing the same work. However we need a thread-safe way to create the `Task` instance, so we can combine it with `Lazy<T>` like this:

```csharp
readonly Lazy<Task<string>> _lazyAccessToken = new Lazy<Task<string>>(async () => {
    return await RetrieveAccessTokenAsync();
});
  
public Task<string> AccessToken => _lazyAccessToken.Value;
```

I've written this verbosely to be clear, but we can reduce this by making the statement a lambda, eliding the await, and replacing the invocation of `RetrieveAccessTokenAsync` with the method group like this:

```csharp
readonly Lazy<Task<string>> _lazyAccessToken = new Lazy<Task<string>>(RetrieveAccessTokenAsync);

public Task<string> AccessToken => _lazyAccessToken.Value;
```

Note that it's important to defer the accessing of `.Value`.

We could encapsulate into a type like this:

```csharp
internal sealed class AsyncLazy<T> : Lazy<Task<T>>
{
    public AsyncLazy(Func<Task<T>> taskFactory) :
    base(taskFactory) { }
}
```

Or we could use the great [vs-threading](https://github.com/Microsoft/vs-threading/) library from Microsoft (if you can get over the VisualStudio namespace), which contains lots of well-polished async primitives such as `AsyncLazy<T>` you would almost expect to come included with the framework and part of .NET Standard.

Also, an honourable mention goes to [AsyncLazy<T>](https://github.com/StephenCleary/AsyncEx/blob/daa22bf7721abd182201661cf7414e7d614ffde6/src/Nito.AsyncEx.Coordination/AsyncLazy.cs) defined in `Nito.AsyncEx.Coordination` by Stephen Cleary.

An alternative strategy to `AsyncLazy<T>` if you don't require it to be lazy, is to eagerly assign a field or property with a task in a constructor, which is started but not awaited, like this:

```csharp
class ApiClient
{
    public ApiClient()
    {
        AccessToken = RetrieveAccessTokenAsync();
    }
  
    public Task<string> AccessToken { get; }
    // here AccessToken is a hot Task, that may or may not be complete by the time it's first accessed
```

### Async & Lock

Another thing that trips people up when migrating their synchronous code is dealing with `lock` blocks, where async code cannot go. First I say, what are you trying to achieve? If it's thread-safe initialization of a resource or singleton, then use Lazy/AsyncLazy mentioned above, your code will likely be cleaner and express your intent better.

If you do need a `lock` block which contains async code, try using a `SemaphoreSlim`. `SemaphoreSlim` does a bit more than `Monitor` and what you need for a `lock` block, but you can use it in a way that gives you the same behaviour. By initializing the `SemaphoreSlim` with an initial value of 1, and a maximum value of 1, we can use it to get thread-safe gated access to some region of code that guarantees exclusive execution.

```csharp
_semaphore = new SemaphoreSlim(1,1) // initial: 1, max: 1  

async Task MyMethod(CancellationToken cancellationToken = default)
{
    await _semaphore.WaitAsync(cancellationToken);
    try
    {
        // the following line will only ever be called by one thread at any time
        await SomethingAsync();
    }
    finally
    {
        _semaphore.Release();
    }
}
```

What's also cool is that `SemaphoreSlim` has a synchronous `Wait` method in addition to `WaitAsync`, so we can use it in scenarios where we need both synchronous and asynchronous access (be careful of course).

It may also be worth checking out `AsyncLock` from `Nito.AsyncEx.Coordination`.

That's it for now, a bit of a random assortment I know.

**Update:** Thanks to Thomas Levesque for pointing out in the comments that `SemaphoreSlim` differs from `Monitor`/`lock` because it is not reentrant. This means a lock has no issue being acquired from a thread that has already acquired it, whereas with a `SemaphoreSlim` you would end up deadlocking yourself under the same scenario.

Another caveat feedback by [odinserj](https://disqus.com/by/odinserj/) in the comments is that on .NET Framework, a thread abort exception could leave the semaphore forever depleted, so it's not bulletproof.