Double await in one call

I was watching a video called Becoming a C# Time Lord and at 0:35:36 this code popped up:

    async Task<TResult[]> PurelyWhenAll<TResult> (params Task<TResult>[] tasks)
    {
        var killJoy = new TaskCompletionSource<TResult[]>();

        foreach ( var task in tasks )
            task.ContinueWith(ant => 
            {
                if ( ant.IsCanceled )
                    killJoy.TrySetCanceled();
                else if ( ant.IsFaulted )
                    killJoy.TrySetException(ant.Exception.InnerException);
            });

        return await await Task.WhenAny(killJoy.Task, Task.WhenAll(tasks));
    }

Does this mean that a task returns a task and because of that we have double await? If that is the case what happens concerning performance if we have more than two awaits? Is this good practice, should this be avoided?

Jon Skeet
people
quotationmark

Task.WhenAny is going to return a Task<Task<TResult>>:

  • Awaiting the result of Task.WhenAny() will return the first task that completed
  • Awaiting that task will return the results of the task, i.e. a TResult[].

You might find it easy to understand with explanatory variables:

var firstCompletedTask = await Task.WhenAny(killJoy.Task, Task.WhenAll(tasks));
var firstResult = await firstCompletedTask;
return firstResult;

It's not clear why you're concerned around the performance of this - it's just two await expressions, not particularly different to any other method with two await expressions.

It's pretty natural to do this when using Task.WhenAny<TResult>(Task<TResult>[]), given that the return type is a Task<Task<TResult>>.

people

See more on this question at Stackoverflow