Does Using Async Await Avoid Thread Exhaustion? - c#

We are troubleshooting the following performance issues on a .NET Core API endpoint:
The endpoint consistently returns in less than 500MS under minor load.
When we hit the endpoint from 3 browsers, with one request a second, it gets progressively slower (within a minute of adding a third browser making calls, response times drops to 50,000MS or worse.
Each additional browser adds threads used by the API, e.g. 40 threads base, 2nd browser hitting endpoint leads to 52 threads, third spikes to 70, and so on.
When one endpoint is loaded, the entire API returns slowly (all endpoints). This is my main reason for thinking "thread exhaustion", along with point #3.
The code currently looks like this:
public IActionResult GetPresentationByEvent(int eventid)
{
return Authorized(authDto =>
{
var eventList = _eventService.GetPresentationByEvent(eventid);
return Ok(eventList)
})
}
My theory is that return Authorized(authDto => holds a thread until it returns, leading to thread exhaustion.
public async Task<IActionResult> GetPresentationByEvent(int eventid)
{
return Authorized(async authDto =>
{
Task<List<whatever>> eventList = _eventService.GetPresentationByEvent(eventid);
return Ok(eventList)
}
}
Authorized is part of a third-party library, so I can't test this easily. Would like to know if this looks like a likely problem/solution.

Yes async await can reduce thread exhaustion. In a few words thread exhaustion arise when you generate more tasks than your ThreadPool can handle.
There are subtle specifities that you can check here : Thread starvation and queuing
The only thing that you have to keep in mind on your side is that you should never block inside a task. This implies calling asynchronous code with async await (and never using .Wait or .Result on a non finished task).
If you use some blocking code wich is not using the async await pattern you have to spawn it on a dedicated thread (not the task thread queue).

My theory is that return Authorized(authDto => holds a thread until it returns, leading to thread exhaustion.
Yes. You can easily tell whether a method is synchronous by looking at its return value. IActionResult is not an awaitable type, so this method will run synchronously.
Authorized is part of a third-party library, so I can't test this easily. Would like to know if this looks like a likely problem/solution.
Possibly. It all depends on whether Authorized can handle asynchronous delegates. If it can, then something like this would work:
public async Task<IActionResult> GetPresentationByEvent(int eventid)
{
return Authorized(async authDto =>
{
Task<List<whatever>> eventList = _eventService.GetPresentationByEventAsync(eventid);
return Ok(await eventList);
});
}
Note:
Tasks should be awaited before being passed to Ok or other helpers.
This introduces GetPresentationByEventAsync, assuming that your data-accessing code can be made asynchronous.
Since making GetPresentationByEvent asynchronous may take some work, it's worthwhile to investigate whether Authorized can take asynchronous delegates before attempting this.
Does Using Async Await Avoid Thread Exhaustion?
Yes and no. Asynchronous code (including async/await) does use fewer threads, since it avoids blocking threads. However, there is still a limit. Thread exhaustion is still possible since asynchronous code needs a free thread to complete. With asynchronous code, usually you can achieve an order of magnitude or two greater scalability before you run into scalability problems like thread exhaustion.
For more conceptual information on async ASP.NET, see this MSDN article.

Related

What is the benefit of C# async/await if it still waits for the previous execution to complete?

I tried reading many articles and questions in stackoverflow regarding the real use of async/await, so basically asynchronous method calls but somehow I am still not able to decode of how does it provide parallelism and non blocking behavior. I referred few posts like these
Is it OK to use async/await almost everywhere?
https://news.ycombinator.com/item?id=19010989
Benefits of using async and await keywords
So if I write a piece of code like this
var user = await GetUserFromDBAsync();
var destination = await GetDestinationFromDBAsync();
var address = await GetAddressFromDBAsync();
Even though all the three methods are asynchronous but still the code will not go to the second line to get destination from database until it fully gets the user from the database.
So where is the parallelism and non blocking behavior of asyn/await here. It still waits to complete the first operation before executing the next line.
Or my total understanding is wrong about asyn?
EDIT
Any example would really help!
The point of async/await is not that methods are executed more quickly. Rather, it's about what a thread is doing while those methods are waiting for a response from a database, the file system, an HTTP request, or some other I/O.
Without asynchronous execution the thread just waits. It is, in a sense, wasted, because during that time it is doing nothing. We don't have an unlimited supply of threads, so having threads sit and wait is wasteful.
Async/await simply allows threads to do other things. Instead of waiting, the thread can serve some other request. And then, when the database query is finished or the HTTP request receives a response, the next available thread picks up execution of that code.
So yes, the individual lines in your example still execute in sequence. They just execute more efficiently. If your application is receiving many requests, it can process those requests sooner because more threads are available to do work instead of blocking, just waiting for a response from some I/O operation.
I highly recommend this blog post: There Is No Thread. There is some confusion that async/await is about executing something on another thread. It is not about that at all. It's about ensuring that no thread is sitting and waiting when it could be doing something else.
You can execute them in parallel/concurrently and still await them in non-blocking manner withTask.WhenAll. You don't have to await each single async method call individually.
So you have the performance gain and at the same time a responsive UI:
//create 3 "cold" tasks, that are not yet running
var userTask = GetUserFromDBAsync();
var destinationTask = GetDestinationFromDBAsync();
var addressTask = GetAddressFromDBAsync();
//start running and awaiting all of them at (almost) the same time
await Task.WhenAll(userTask, destinationTask, adressTask);
//get the cached results
var user = userTask.Result;
var destination = destinationTask.Result;
var address = addressTask.Result;

Does async (one task) make sense in MVC?

I am using async/await in MVC, but only when I have more than one task (WaitAll).
I understand that having only one task is good to have the UI free, in case of WPF or Windows Form, but does it make sense for MVC to have only one task and await for that?
I've seen it a lot in code, in MVC, but I don't get the advantages.
HTTP requests are handled by thread pool threads.
If you block a thread, it will not be able to do other work. Because the total number of threads is limited, this can led to the starvation of the thread pool and new requests will be denied - 503.
Using async code, the thread is released back to the thread pool, becoming available to handle new requests or the continuations of async code.
Like on client UIs, on the server, async code is all about responsiveness, not performance. Requests will take longer but your server will be able to handle more requests.
It depends on what you are trying to achieve. For instance, if you have multiple calls to multiple services you can always do it in a way that only the last call makes the rest of the system "wait".
You can optimise your code in a way that X asynchronously calls to services start (almost) at the same time without having to 'await' for one another.
public async Task RunSomethings()
{
var something1 = AsyncCall1();
var something2 = AsyncCall2();
var something3 = await AsyncCall3();
}
private async Task<Something1> AsyncCall1()
{
return await Something1();
}
private async Task<Something2> AsyncCall2()
{
return await Something2();
}
private async Task<Something3> AsyncCall3()
{
return await Something3();
}
I hope it helps.
Good question. Using asynchronous methods is all about using the resources effectively as well as give a good user experience. Any time you need to call on a resource that could take time to collect, it's good to use an async call.
This will do a few things. First, while a worker thread is waiting for data, it can be put on 'hold' so to speak, and that worker thread can do something else until the data is returned, an error is returned or the call just times out.
This will give you the second advantage. The interface the user is using to call the resource will be released, temporarily, to do other things. And overall, less server resources are consumed by idle processes.
I'd recommend watching the videos on this page here: https://channel9.msdn.com/Series/Three-Essential-Tips-for-Async
It's probably the clearest explanation that can help leapfrog your learning on async.

Async not working as I expected

I've read all I can find on async programming in asp.net (c#). I've made sense of most of how it's supposed to work and when it should be used. Yet I find basic examples not working as I expect. Without Task.Run it doesn't seem to actually run asynchronously.
Can someone tell me what I'm missing in this example?
Say the code is like so
public async Task SubTask2()
{
LongRunningOperation2();
Response.Write("<br>------------------------ Finished -------------------------<br>");
}
private async Task<Boolean> LongRunningOperation1()
{
int counter;
for (counter = 0; counter < 50000; counter++)
{
Response.Write(counter + "<br>");
}
return await Task.FromResult<bool>(true);
}
private async Task<Boolean> LongRunningOperation2()
{
await LongRunningOperation1();
Response.Write("<br>------------------------ Long Task -------------------------<br>");
return true;
}
Shouldn't LongRunningOperation2() return to SubTask2() and print "finished" before or while writing out numbers? Instead it prints finished at the end. Using Task.Run works as expected but then I don't see the point of ever not using Task.Run
A design consideration of the async/await pattern is that sometimes code that has an async signature might return synchronously (immediately) - perhaps due to caching or local data buffering (reading data from a socket, perhaps, and having spare data left to consume from the buffer), or perhaps due to IoC etc providing a synchronous implementation of an asynchronous signature. In that scenario, the entire engine is designed to optimize by not doing anything as callbacks, but continuing to run synchronously. This is not an edge-case - recent C# updates have extended this by adding support for custom awaitables (in particular: ValueTask<T>) to make this even more efficient in the case when something completes with a synchronous but non-trivial result.
The purpose of async is to facilitate scenarios that have genuinely async components, freeing up the thread to do more useful things than waiting for an async operation to complete. It is not about parallelization.
In your case, all of your code is actually synchronous, so it continues to run synchronously all the way through.
First, you're missing await in SubTask2(), so it actually runs synchronously (waits for LongRunningOperation2() to finish).
Secondly, even with asynchronous execution, "finished" wouldn't be printed before LongRunningOperation2() finished it's work. The point of using it is to free the thread, so it can do some other work in the meantime (e.g. handle another request).

Effectively use async/await with ASP.NET Web API

I am trying to make use of the async/await feature of ASP.NET in my Web API project. I am not very sure whether it will make any difference in performance of my Web API service. Please find below the workflow and sample code from my application.
Work Flow:
UI Application → Web API endpoint(controller) → Call method in Web API service layer → Call another external web service. (Here we have the DB interactions, etc.)
Controller:
public async Task<IHttpActionResult> GetCountries()
{
var allCountrys = await CountryDataService.ReturnAllCountries();
if (allCountrys.Success)
{
return Ok(allCountrys.Domain);
}
return InternalServerError();
}
Service Layer:
public Task<BackOfficeResponse<List<Country>>> ReturnAllCountries()
{
var response = _service.Process<List<Country>>(BackOfficeEndpoint.CountryEndpoint, "returnCountries");
return Task.FromResult(response);
}
I tested the above code and is working. But I am not sure whether it is the correct usage of async/await. Please share your thoughts.
I am not very sure whether it will make any difference in performance of my API.
Bear in mind that the primary benefit of asynchronous code on the server side is scalability. It won't magically make your requests run faster. I cover several "should I use async" considerations in my article on async ASP.NET.
I think your use case (calling other APIs) is well-suited for asynchronous code, just bear in mind that "asynchronous" does not mean "faster". The best approach is to first make your UI responsive and asynchronous; this will make your app feel faster even if it's slightly slower.
As far as the code goes, this is not asynchronous:
public Task<BackOfficeResponse<List<Country>>> ReturnAllCountries()
{
var response = _service.Process<List<Country>>(BackOfficeEndpoint.CountryEndpoint, "returnCountries");
return Task.FromResult(response);
}
You'd need a truly asynchronous implementation to get the scalability benefits of async:
public async Task<BackOfficeResponse<List<Country>>> ReturnAllCountriesAsync()
{
return await _service.ProcessAsync<List<Country>>(BackOfficeEndpoint.CountryEndpoint, "returnCountries");
}
Or (if your logic in this method really is just a pass-through):
public Task<BackOfficeResponse<List<Country>>> ReturnAllCountriesAsync()
{
return _service.ProcessAsync<List<Country>>(BackOfficeEndpoint.CountryEndpoint, "returnCountries");
}
Note that it's easier to work from the "inside out" rather than the "outside in" like this. In other words, don't start with an asynchronous controller action and then force downstream methods to be asynchronous. Instead, identify the naturally asynchronous operations (calling external APIs, database queries, etc), and make those asynchronous at the lowest level first (Service.ProcessAsync). Then let the async trickle up, making your controller actions asynchronous as the last step.
And under no circumstances should you use Task.Run in this scenario.
It is correct, but perhaps not useful.
As there is nothing to wait on – no calls to blocking APIs which could operate asynchronously – then you are setting up structures to track asynchronous operation (which has overhead) but then not making use of that capability.
For example, if the service layer was performing DB operations with Entity Framework which supports asynchronous calls:
public Task<BackOfficeResponse<List<Country>>> ReturnAllCountries()
{
using (db = myDBContext.Get()) {
var list = await db.Countries.Where(condition).ToListAsync();
return list;
}
}
You would allow the worker thread to do something else while the db was queried (and thus able to process another request).
Await tends to be something that needs to go all the way down: it is very hard to retro-fit into an existing system.
You are not leveraging async / await effectively because the request thread will be blocked while executing the synchronous method ReturnAllCountries()
The thread that is assigned to handle a request will be idly waiting while ReturnAllCountries() does it's work.
If you can implement ReturnAllCountries() to be asynchronous, then you would see scalability benefits. This is because the thread could be released back to the .NET thread pool to handle another request, while ReturnAllCountries() is executing. This would allow your service to have higher throughput, by utilizing threads more efficiently.
I would change your service layer to:
public Task<BackOfficeResponse<List<Country>>> ReturnAllCountries()
{
return Task.Run(() =>
{
return _service.Process<List<Country>>(BackOfficeEndpoint.CountryEndpoint, "returnCountries");
}
}
as you have it, you are still running your _service.Process call synchronously, and gaining very little or no benefit from awaiting it.
With this approach, you are wrapping the potentially slow call in a Task, starting it, and returning it to be awaited. Now you get the benefit of awaiting the Task.

Wrapping synchronous code into asynchronous call

I have a method in ASP.NET application, that consumes quite a lot of time to complete. A call to this method might occur up to 3 times during one user request, depending on the cache state and parameters that user provides. Each call takes about 1-2 seconds to complete. The method itself is synchronous call to the service and there is no possibility to override the implementation.
So the synchronous call to the service looks something like the following:
public OutputModel Calculate(InputModel input)
{
// do some stuff
return Service.LongRunningCall(input);
}
And the usage of the method is (note, that call of method may happen more than once):
private void MakeRequest()
{
// a lot of other stuff: preparing requests, sending/processing other requests, etc.
var myOutput = Calculate(myInput);
// stuff again
}
I tried to change the implementation from my side to provide simultaneous work of this method, and here is what I came to so far.
public async Task<OutputModel> CalculateAsync(InputModel input)
{
return await Task.Run(() =>
{
return Calculate(input);
});
}
Usage (part of "do other stuff" code runs simultaneously with the call to service):
private async Task MakeRequest()
{
// do some stuff
var task = CalculateAsync(myInput);
// do other stuff
var myOutput = await task;
// some more stuff
}
My question: Do I use the right approach to speed up the execution in ASP.NET application or am I doing unnecessary job trying to run synchronous code asynchronously?
Can anyone explain why the second approach is not an option in ASP.NET (if it is really not)?
Also, if such approach is applicable, do I need to call such method asynchronously if it is the only call we might perform at the moment (I have such case, when no other stuff there is to do while waiting for completion)?
Most of the articles in the net on this topic covers using async-await approach with the code, that already provides awaitable methods, but that's not my case. Here is the nice article describing my case, which doesn't describe the situation of parallel calls, declining the option to wrap sync call, but in my opinion my situation is exactly the occasion to do it.
It's important to make a distinction between two different types of concurrency. Asynchronous concurrency is when you have multiple asynchronous operations in flight (and since each operation is asynchronous, none of them are actually using a thread). Parallel concurrency is when you have multiple threads each doing a separate operation.
The first thing to do is re-evaluate this assumption:
The method itself is synchronous call to the service and there is no possibility to override the implementation.
If your "service" is a web service or anything else that is I/O-bound, then the best solution is to write an asynchronous API for it.
I'll proceed with the assumption that your "service" is a CPU-bound operation that must execute on the same machine as the web server.
If that's the case, then the next thing to evaluate is another assumption:
I need the request to execute faster.
Are you absolutely sure that's what you need to do? Are there any front-end changes you can make instead - e.g., start the request and allow the user to do other work while it's processing?
I'll proceed with the assumption that yes, you really do need to make the individual request execute faster.
In this case, you'll need to execute parallel code on your web server. This is most definitely not recommended in general because the parallel code will be using threads that ASP.NET may need to handle other requests, and by removing/adding threads it will throw the ASP.NET threadpool heuristics off. So, this decision does have an impact on your entire server.
When you use parallel code on ASP.NET, you are making the decision to really limit the scalability of your web app. You also may see a fair amount of thread churn, especially if your requests are bursty at all. I recommend only using parallel code on ASP.NET if you know that the number of simultaneous users will be quite low (i.e., not a public server).
So, if you get this far, and you're sure you want to do parallel processing on ASP.NET, then you have a couple of options.
One of the easier methods is to use Task.Run, very similar to your existing code. However, I do not recommend implementing a CalculateAsync method since that implies the processing is asynchronous (which it is not). Instead, use Task.Run at the point of the call:
private async Task MakeRequest()
{
// do some stuff
var task = Task.Run(() => Calculate(myInput));
// do other stuff
var myOutput = await task;
// some more stuff
}
Alternatively, if it works well with your code, you can use the Parallel type, i.e., Parallel.For, Parallel.ForEach, or Parallel.Invoke. The advantage to the Parallel code is that the request thread is used as one of the parallel threads, and then resumes executing in the thread context (there's less context switching than the async example):
private void MakeRequest()
{
Parallel.Invoke(() => Calculate(myInput1),
() => Calculate(myInput2),
() => Calculate(myInput3));
}
I do not recommend using Parallel LINQ (PLINQ) on ASP.NET at all.
I found that the following code can convert a Task to always run asynchronously
private static async Task<T> ForceAsync<T>(Func<Task<T>> func)
{
await Task.Yield();
return await func();
}
and I have used it in the following manner
await ForceAsync(() => AsyncTaskWithNoAwaits())
This will execute any Task asynchronously so you can combine them in WhenAll, WhenAny scenarios and other uses.
You could also simply add the Task.Yield() as the first line of your called code.
this is probably the easiest generic way in your case
return await new Task(
new Action(
delegate () {
// put your synchronous code here
}
)
);

Categories

Resources