Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I avoid thread pool exhaustion and deadlocks in this .NET Core Web API using async/await?

I’m working on a .NET Core Web API, and I’ve encountered performance issues and potential deadlocks when calling asynchronous methods. I suspect that I'm using async and await incorrectly. Below is the code that illustrates my issue:

public class ExampleController : ControllerBase
{
    private readonly IDataService _dataService;

    public ExampleController(IDataService dataService)
    {
        _dataService = dataService;
    }

    [HttpGet("get-data")]
    public IActionResult GetData()
    {
        var data = _dataService.GetDataAsync().Result;

        // Simulating long-running blocking operation
        Task.Delay(5000).Wait();

        return Ok(data);
    }
}

public class DataService : IDataService
{
    public async Task<List<string>> GetDataAsync()
    {
        await Task.Delay(1000); // Simulating I/O-bound work
        return new List<string> { "item1", "item2", "item3" };
    }
}

What I’m concerned about:

I’m using .Result to call an asynchronous method synchronously. Could this cause a deadlock or thread pool exhaustion? I’m using Task.Delay().Wait() to simulate a long-running task. Is there a better way to handle such delays asynchronously? What are the best practices for using async and await in this scenario to avoid performance issues like deadlocks or thread pool exhaustion?

I tried calling the asynchronous method synchronously using .Result, expecting the method to return the result without blocking the thread. However, the application experienced performance degradation, and in some cases, it led to thread pool exhaustion, slowing down the API response times.

like image 941
Perturbator Avatar asked Oct 28 '25 20:10

Perturbator


1 Answers

I’m using .Result to call an asynchronous method synchronously. Could this cause a deadlock or thread pool exhaustion?

It should not cause a deadlock in a server, but it might cause thread pool exhaustion. Your method should return a task, and might look something like

[HttpGet("get-data")]
public async Task<List<string>> GetMyData()
{
    var data = await _dataService.GetDataAsync().

    // do further processing
    return data;
}

Or use Task<IAsyncResult> as the result type, this seem to be mostly a matter of preference.

I’m using Task.Delay().Wait() to simulate a long-running task. Is there a better way to handle such delays asynchronously?

That depend on the task. If it is really CPU bound you need the CPU time to run it, there is no way around that, except to somehow optimize the task.

But 5000ms is extremely long CPU bound time for a web request, they should normally be a few ms. There are some tasks that really need that much time, but then you need to build the both the web server and service with that in mind. Note that using .Wait() is not a great way to simulate CPU bound tasks, since there is no actual CPU load, so the scheduler is free to run other threads while your thread is waiting, resulting in the pool exhaustion.

What are the best practices for using async and await in this scenario to avoid performance issues like deadlocks or thread pool exhaustion?

  1. await all returned tasks. Avoid .Result and .Wait().
  2. avoid async void whenever possible. Always return a Task when you can.
like image 116
JonasH Avatar answered Oct 31 '25 12:10

JonasH



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!