Fire And Forget Tasks

This post demonstrates a couple of different ways to execute fire and forget tasks in C#.

In C#, sometimes you want to start a Task but you don't care about waiting for the result. But even though you may not care about the result of the task or how long it takes to complete, you shouldn't ignore the possibility of an error. At the very least, you'll probably want to log the error.

There are at least a couple of ways to execute fire and forget tasks. The first way is by running the task with a continuation. Here's how that's done.

static void FireAndForgetExample1(Task taskToForget)
{
    _ = taskToForget.ContinueWith(t =>
    {
        if (t.IsFaulted)
        {
            // Log the exception.
        }
    });
}
Fire and forget with a continuation

The previous example uses ContinueWith which was popular before the async and await keywords were introduced. It's now preferred to use the new key words instead of the older continuation style. Here are a couple of reasons why:

  • It's easier to debug: The await keyword creates a state machine when your code is compiled and that state machine aids in your debugging.
  • It's optimized: As mentioned above, the await keyword creates a state machine that is optimized for execution and can continue to be optimized in the future. One such optimization is that completed tasks return immediately. Conversely, ContinueWith is less efficient because it must allocate a continuation task for each continuation.

Here's how to execute fire and forget tasks using a local function, which takes advantage of the async and await keywords.

static void FireAndForgetExample2(Task taskToForget)
{
    async Task Forget(Task task)
    {
        try
        {
            await task;
        }
        catch (Exception ex)
        {
            // Log the exception.
        }
    }
    _ = Forget(taskToForget);
}
Fire and forget with a local function