Search code examples
c#asynchronousasync-awaittaskasp.net-4.8

Is there a reason to run a Task within another Task?


I found this method in an ASP.NET application:

public void LogoutAllSessions()
{
    Task.Run(async () => await _identityHttpClient.GetAsync(Uri)).Wait();

    // Could this be rewritten as this:?
    // _identityHttpClient.GetAsync(Uri).GetAwaiter().GetResult();
}

Is this just running a task within another task and blocking the thread while it waits for the outer task to finish?

I was told it was written like this because updating it to just use plain async/await would involve changing too many methods up the stack.

Would _identityHttpClient.GetAsync(Uri).GetAwaiter().GetResult(); do the same thing as Task.Run(async () => await _identityHttpClient.GetAsync(Uri)).Wait();?

Would one be faster than the other?


Solution

  • There is indeed a reason to wrap the asynchronous method GetAsync in Task.Run before waiting it synchronously with .Wait() or .GetAwaiter().GetResult(). The reason is to prevent a deadlock in case the GetAsync is implemented with async/await, there is a SynchronizationContext installed on the current thread (typical for GUI applications), there is an await inside the GetAsync not configured with .ConfigureAwait(false), and the awaitable (Task) is not already completed at the await point. Under these conditions the deadlock happens consistently (without Task.Run), you'll observe it immediately during the testing (the application will hang), and you'll be forced to fix it. Wrapping the call with Task.Run is one way to fix it, because the Task.Run invokes the asynchronous method on the ThreadPool, where there is no SynchronizationContext installed. If you remove the Task.Run and your application does not hang, most likely the Task.Run is redundant.

    The effect that a redundant Task.Run has on performance is negligible. It can be either beneficial or detrimental, but the difference will be minuscule.

    To understand the reason for the deadlock, you could take a look at this question: An async/await example that causes a deadlock.