Do nested async/await calls give any performance boost?

Viewed 157

This is somewhat related to Why use Async/await all the way down . I have some legacy EF Core I need to maintain with lots of nested calls that are not async. I am wondering if it is just ok to make the top level controller only async and wrap the service call with a Task.Run().

What is the difference between these 2 controller actions. In the first one, EF core is called synchronously. But the call is wrapped in a Task.Run so I assume it will be executed asynchronously

In the second, the EF core calls is async But is it even necessary since the controller action is async? Will async within async within async... give any performance boost over just one async call at the top?

case 1

    //controller, async call
    public async Task<ActionList<string>> GetNames()
    {
        var names = await Task.Run(() => peopleService.GetNames());
        return Ok(names);
    }

//people service layer, no async
public List<string> GetNames()
{
    return _context.People.Where(...).Select(x => x.Name).ToList();
}

case 2

//controller, async
public async Task<ActionList<string>> GetNames()
{
    var names = await  peopleService.GetNames();
    return Ok(names);
}

//people service layer, async
public async Task<List<string>> GetNamesAsync()
{
    return await _context.People.Where(...).Select(x => x.Name).ToListAsync();
}


1 Answers

Task.Run only serves to run your code on the thread pool. This can be useful for WPF or WinForms applications, since it frees up the UI thread to continue processing other UI events. However, it does not bring any performance benefits in ASP.NET, since you're just switching execution from one thread-pool thread to another. When it encounters the EF ToList call, this thread-pool thread will get blocked. If you have a lot of concurrent requests, the thread pool will get exhausted. .NET has a thread injection policy, but this is limited, so some requests will time out. If your load gets very high, you will need so many threads that you will deplete your system resources (CPU and memory).

By contrast, async-all-the-way means that you are never blocking any threads while the database I/O operations are in progress. Each asynchronous operation is handled by the underlying system, and execution only resumes on the thread pool once the operation has completed. This allows your system to scale to a much larger number of concurrent requests.

Related