Await Now or Never


This post is a continuation of implementing a custom scheduler for your orchestrations. We saw that the Delay operation is either completed or results in a never ending task, that nobody ever completes. Could we make it easier and provide a better way for delaying operation?

Complete or not, here I come

The completed Delay operation was realized by


This is a static readonly instance of a task that is already completed. If you need to return a completed task, because the operation of your asynchronous method was done synchronously, this is the best way you can do it.

For cases where we don’t want continuations to be run, we used:

new TaskCompletionSource<object>().Task

which of course allocates both, the TaskCompletionSource instance and the underlying Task object. It’s not that much, but maybe, as there are only two states of the continuation: now or never, we could provide a smaller tool for this, that does not allocate.

Now OR Never

You probably know, that you might create your custom awaitable objects, that you don’t need to await on Tasks only. Let’s take a look at the following class

public sealed class NowOrNever : ICriticalNotifyCompletion
  public static readonly NowOrNever Never = new NowOrNever(false);
  public static readonly NowOrNever Now = new NowOrNever(true);

  NowOrNever(bool isCompleted)
    IsCompleted = isCompleted;

  public NowOrNever GetAwaiter()
    return this;

  public void GetResult() { }

  public bool IsCompleted { get; }

  public void OnCompleted(Action continuation) { }

  public void UnsafeOnCompleted(Action continuation) { }

This class is awaitable, as it provides three elements:

  1. IsCompleted – for checking whether it was finished (fast enough or synchronously to do not build whole machinery for an asynchronous dispatch)
  2. GetAwaiter – to obtain the awaiter that is used to create the asynchronous flow
  3. GetResult

Knowing what are these parts for, let’s take a look at different values provided by NowOrNever static fields

NowOrNever IsCompleted OnCompleted/ UnsafeOnCompleted
Now true no action
Never false no action


As you can see, the completion is never called at all. For the Never case, that’s what we meant. What about Now? Just take a look above. Whenever IsCompleted is true, no continuations are attached, and the code is executed synchronously. We don’t need to preserve continuations as there are none.


Writing a custom awaitable class is not a day-to-day activity. Sometimes there are cases where this could have its limited benefit. In this NowOrNever case, this allowed to skip the allocation of a single task, although, yes, the created async state machine takes probably much more that a single task instance.