async and await: are they bad? - performance

We recently developed a site based on SOA but this site ended up having terrible load and performance issues when it went under load. I posted a question related this issue here:
ASP.NET website becomes unresponsive under load
The site is made of an API (WEB API) site which is hosted on a 4-node cluster and a web site which is hosted on another 4-node cluster and makes calls to the API. Both are developed using ASP.NET MVC 5 and all actions/methods are based on async-await method.
After running the site under some monitoring tools such as NewRelic, investigating several dump files and profiling the worker process, it turned out that under a very light load (e.g. 16 concurrent users) we ended up having around 900 threads which utilized 100% of CPU and filled up the IIS thread queue!
Even though we managed to deploy the site to the production environment by introducing heaps of caching and performance amendments many developers in our team believe that we have to remove all async methods and covert both API and the web site to normal Web API and Action methods which simply return an Action result.
I personally am not happy with approach because my gut feeling is that we have not used the async methods properly otherwise it means that Microsoft has introduced a feature that basically is rather destructive and unusable!
Do you know any reference that clears it out that where and how async methods should/can be used? How we should use them to avoid such dramas? e.g. Based on what I read on MSDN I believe the API layer should be async but the web site could be a normal no-async ASP.NET MVC site.
Update:
Here is the async method that makes all the communications with the API.
public static async Task<T> GetApiResponse<T>(object parameters, string action, CancellationToken ctk)
{
using (var httpClient = new HttpClient())
{
httpClient.BaseAddress = new Uri(BaseApiAddress);
var formatter = new JsonMediaTypeFormatter();
return
await
httpClient.PostAsJsonAsync(action, parameters, ctk)
.ContinueWith(x => x.Result.Content.ReadAsAsync<T>(new[] { formatter }).Result, ctk);
}
}
Is there anything silly with this method? Note that when we converted all method to non-async methods we got a heaps better performance.
Here is a sample usage (I've cut the other bits of the code which was related to validation, logging etc. This code is the body of a MVC action method).
In our service wrapper:
public async static Task<IList<DownloadType>> GetSupportedContentTypes()
{
string userAgent = Request.UserAgent;
var parameters = new { Util.AppKey, Util.StoreId, QueryParameters = new { UserAgent = userAgent } };
var taskResponse = await Util.GetApiResponse<ApiResponse<SearchResponse<ProductItem>>>(
parameters,
"api/Content/ContentTypeSummary",
default(CancellationToken));
return task.Data.Groups.Select(x => x.DownloadType()).ToList();
}
And in the Action:
public async Task<ActionResult> DownloadTypes()
{
IList<DownloadType> supportedTypes = await ContentService.GetSupportedContentTypes();

Is there anything silly with this method? Note that when we converted
all method to non-async methods we got a heaps better performance.
I can see at least two things going wrong here:
public static async Task<T> GetApiResponse<T>(object parameters, string action, CancellationToken ctk)
{
using (var httpClient = new HttpClient())
{
httpClient.BaseAddress = new Uri(BaseApiAddress);
var formatter = new JsonMediaTypeFormatter();
return
await
httpClient.PostAsJsonAsync(action, parameters, ctk)
.ContinueWith(x => x.Result.Content
.ReadAsAsync<T>(new[] { formatter }).Result, ctk);
}
}
Firstly, the lambda you're passing to ContinueWith is blocking:
x => x.Result.Content.ReadAsAsync<T>(new[] { formatter }).Result
This is equivalent to:
x => {
var task = x.Result.Content.ReadAsAsync<T>(new[] { formatter });
task.Wait();
return task.Result;
};
Thus, you're blocking a pool thread on which the lambda is happened to be executed. This effectively kills the advantage of the naturally asynchronous ReadAsAsync API and reduces the scalability of your web app. Watch out for other places like this in your code.
Secondly, an ASP.NET request is handled by a server thread with a special synchronization context installed on it, AspNetSynchronizationContext. When you use await for continuation, the continuation callback will be posted to the same synchronization context, the compiler-generated code will take care of this. OTOH, when you use ContinueWith, this doesn't happen automatically.
Thus, you need to explicitly provide the correct task scheduler, remove the blocking .Result (this will return a task) and Unwrap the nested task:
return
await
httpClient.PostAsJsonAsync(action, parameters, ctk).ContinueWith(
x => x.Result.Content.ReadAsAsync<T>(new[] { formatter }),
ctk,
TaskContinuationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext()).Unwrap();
That said, you really don't need such added complexity of ContinueWith here:
var x = await httpClient.PostAsJsonAsync(action, parameters, ctk);
return await x.Content.ReadAsAsync<T>(new[] { formatter });
The following article by Stephen Toub is highly relevant:
"Async Performance: Understanding the Costs of Async and Await".
If I have to call an async method in a sync context, where using await
is not possible, what is the best way of doing it?
You almost never should need to mix await and ContinueWith, you should stick with await. Basically, if you use async, it's got to be async "all the way".
For the server-side ASP.NET MVC / Web API execution environment, it simply means the controller method should be async and return a Task or Task<>, check this. ASP.NET keeps track of pending tasks for a given HTTP request. The request is not getting completed until all tasks have been completed.
If you really need to call an async method from a synchronous method in ASP.NET, you can use AsyncManager like this to register a pending task. For classic ASP.NET, you can use PageAsyncTask.
At worst case, you'd call task.Wait() and block, because otherwise your task might continue outside the boundaries of that particular HTTP request.
For client side UI apps, some different scenarios are possible for calling an async method from synchronous method. For example, you can use ContinueWith(action, TaskScheduler.FromCurrentSynchronizationContext()) and fire an completion event from action (like this).

async and await should not create a large number of threads, particularly not with just 16 users. In fact, it should help you make better use of threads. The purpose of async and await in MVC is to actually give up the thread pool thread when it's busy processing IO bound tasks. This suggests to me that you are doing something silly somewhere, such as spawning threads and then waiting indefinitely.
Still, 900 threads is not really a lot, and if they're using 100% cpu, then they're not waiting.. they're chewing on something. It's this something that you should be looking into. You said you have used tools like NewRelic, well what did they point to as the source of this CPU usage? What methods?
If I were you, I would first prove that merely using async and await are not the cause of your problems. Simply create a simple site that mimics the behavior and then run the same tests on it.
Second, take a copy of your app, and start stripping stuff out and then running tests against it. See if you can track down where the problem is exactly.

There is a lot of stuff to discuss.
First of all, async/await can help you naturally when your application has almost no business logic. I mean the point of async/await is to do not have many threads in sleep mode waiting for something, mostly some IO, e.g. database queries (and fetching). If your application does huge business logic using cpu for 100%, async/await does not help you.
The problem of 900 threads is that they are inefficient - if they run concurrently. The point is that it's better to have such number of "business" threads as you server has cores/processors. The reason is thread context switching, lock contention and so on. There is a lot of systems like LMAX distruptor pattern or Redis which process data in one thread (or one thread per core). It's just better as you do not have to handle locking.
How to reach described approach? Look at disruptor, queue incoming requests and processed them one by one instead of parallel.
Opposite approach, when there is almost no business logic, and many threads just waits for IO is good place where to put async/await into work.
How it mostly works: there is a thread which reads bytes from network - mostly only one. Once some some request arrive, this thread reads the data. There is also limited thread pool of workers which processes requests. The point of async is that once one processing thread is waiting for some thing, mostly io, db, the thread is returned in poll and can be used for another request. Once IO response is ready, some thread from pool is used to finish the processing. This is the way how you can use few threads to server thousand request in a second.
I would suggest that you should draw some picture how your site is working, what each thread does and how concurrently it works. Note that it's necessary to decide whether throughput or latency is important for you.

Related

FireAndForget call to WebApi from Azure Function

I want to be able to call an HTTP endpoint (that I own) from an Azure Function at the end of the Azure Function request.
I do not need to know the result of the request
If there is a problem in the HTTP endpoint that is called I will log it there
I do not want to hold up the return to the client calling the initial Azure Function
Offloading the call of the secondary WebApi onto a background job queue is considered overkill for this requirement
Do I simply call HttpClient.PutAsync without an await?
I realise that the dependencies I have used up until the point that the call is made may well not be available when the call returns. Is there a safe way to check if they are?
My answer may cause some controversy but, you can always start a background task and execute it that way.
For anyone reading this answer, this is far from recommended. The OP has been very clear that they don't care about exceptions or understanding what sort of result the request is returning ...
Task.Run(async () =>
{
using (var httpClient = new HttpClient())
{
await httpClient.PutAsync(...);
}
});
If you want to ensure that the call has fired, it may be worth waiting for a second or two after the call is made to ensure it's actually on it's way.
await Task.Delay(1000);
If you're worried about dependencies in the call, be sure to construct your payload (i.e. serialise it, etc.) external to the Task.Run, basically, minimise any work the background task does.

ktor server - when to move to another coroutine context

This may be a question about coroutines in general, but in my ktor server (netty engine, default configuration) application I perform serveral asyncronous calls to a database and api endpoint and want to make sure I am using coroutines efficiently. My question are as follows:
Is there a tool or method to work out if my code is using coroutines effectively, or do I just need to use curl to spam my endpoint and measure the performance of moving processes to another context e.g. compute?
I don't want to start moving tasks/jobs to another context 'just in case' but should I treat the default coroutine context in my Route.route() similar to the Android main thread and perform the minimum amount of work on it?
Here is an rough example of the code that I'm using:
fun Route.route() {
get("/") {
call.respondText(getRemoteText())
}
}
suspend fun getRemoteText() : String? {
return suspendCoroutine { cont ->
val document = 3rdPartyLibrary.get()
if (success) {
cont.resume(data)
} else {
cont.resume(null)
}
}
}
You could use something like Apache Jmeter, but writing a script and spamming your server with curl seems also a good option to me
Coroutines are pretty efficient when it comes to context/thread switching, and with Dispatchers.Default and Dispatchers.IO you'll get a thread-pool. There are a couple of documentations around this, but I think you can definitely leverage these Dispatchers for heavy operations
There are few tools for testing endpoints. Jmeter is good, there are also command line tools like wrk, wrk2 and siege.
Of course context switching costs. The coroutine in routing is safe to run blocking operations unless you have the option shareWorkGroup set. However, usually it's good to use a separate thread pool because you can control it's size (max threads number) to not get you database down.

MVC ActionResult trigger Async Task before return View()

I'm trying to achieve something like this:
[HttpPost]
public ActionResult PostData()
{
// 1. Need to trigger an async operation for some long processes
// Trying to trigger SideProcess() async controller
// Return to view to allow user do other stuff without waiting for above process to complete
return View("Listing", "Users");
}
public async Task<ActionResult> SideProcess()
{
...
}
Can I use async task method like above? Because I definitely have to call PostData() first on a button click. Otherwise most likely I have to use a different method.
You can, by not await-ing the result. This has some drawbacks though. (E.g. what happens if an error occurrs?)
It is better to run the async operation in via Task.Run() in such cases, since unhandled exceptions will trigger the TaskScheduler.UnobservedTaskException and don't mess with your controller action.
Task.Run(SideProcess);
I tend to use Hangfire for such problems in all of my projects and never had an issue. I would recommend and prefer it over the above solution. Comes with very handy oob features for managing BackgroundJobs (including a dashboard, automatic retry mechanisms and many more) while beeing testable too.
Doing that, you won't have any guarantees that your long running process will finish. ASP.NET was purposely not built for that.
But if you have to queue some background work, use HostingEnvironment.QueueBackgroundWorkItem.
Beware of the remarks:
Differs from a normal ThreadPool work item in that ASP.NET can keep track of how many work items registered through this API are currently running, and the ASP.NET runtime will try to delay AppDomain shutdown until these work items have finished executing. This API cannot be called outside of an ASP.NET-managed AppDomain. The provided CancellationToken will be signaled when the application is shutting down.

async methods calling sync methods

New to async and trying to understand when it makes sense to use it.
We are going to have lots methods in webapi2 calling legacy webservices.
We have lots of low level dlls (Company.Dal.dll,Company.Biz.dll) etc.. that have methods that are not async
Question
Does async has to be all the way really ?
Is there any benefit of having an high level dll (all method async) calling low level dlls (dal,biz etc legacy code) where none of the method are async?
Is it there any benefit in having just the high level component to be async and the rest syncronous?
Many thanks for clarification
Any good tutorials explaning this concept
Using async only makes sense if you actually await something. If you don't, the async method will actually be completely synchronous (and you get a warning from the compiler about it).
In this case, async doesn't have any advantages, only disadvantages: the code is more complex and less efficient.
A thread can only do one thing at a time. If procedures keep your thread busy, there is no sense in making them async.
However if there are periods where the thread in your procedure has to wait for something else to finish, your thread might do something useful instead. In those circumstances async-await becomes useful.
Eric lippert once explained async-await with a restaurant metaphor (search on the page for async-await). If you have a cook who has to wait until the bread is toasted, this cook could do something else, like cooking an egg, and get back to the toaster when the "something else" is finished, or when has to wait for something, like await for the egg to be cooked.
In software the things where your thread typically will do nothing except waiting for something to finish is when reading / writing to disk, sending or receiving data over the network etc. Those are typically actions where you can find async versions as well as non-async versions of the procedure. See for instance classes like Stream, TextReader, WebClient, etc.
If your thread has to do a lot of calculations, it is not useful to make the function async, because there is no moment your thread will not do anything but wait, so your thread won't have time to do other things.
However, if your thread could do something useful while the calculations are done, consider letting another thread do those calculations while your thread is doing the other useful stuff:
private async Task<int> MyLengthyProcedure(...)
{
Task<int> calculationTask = Task.Run( () => DoCalculations(...));
// while one of the threads is doing the calculations,
// your thread could do other useful things:
int i = DoOtherCalculations();
// or if there are calculations that could be performed
// by separate threads simultaneously, start a second task
Task<int> otherCalculationTask = Task.Run( () => DoEvenMoreCalculations(...));
// now two threads are doing calculations. This thread is still free to
// do other things
// after a while you need the result of both calculations:
await Task.WhenAll( new Task[] {calculationTask, otherCalculationTask});
// the int return value of DoCalculations and DoOtherCalculations are in
// the Result property of the task object:
int j = calculationTask.Result;
int k = otherCalculationTask.Result;
return i + j + k;
;

HttpWebRequest async versus Begin/End

I have a Web API project whose controller in turn makes web requests to a third party REST interface. My controller CRUD functions i have marked as async however the implementation is such that i use HttpWebRequest blocking functions GetRequestStream and GetResponse.
Is this suitable or should i use the Begin/End methods of HttpWebRequest too. This seems like overkill as it would be asyncing an already async operation, or would it allow more concurrent outgoing web requests?
Looking for the best solution for throughput both incoming and outgoing.
the controller is marked async but the implementation uses synchronous HttpWebRequest calls, in that my controller is awaiting Task.Run( sync web request )
Think about what is happening in the request. The request comes in and ASP.NET takes a thread pool thread to handle the request. The controller action queues the work to the thread pool (taking up another thread), and then awaits that work, freeing up the original request thread. You haven't gained anything by using await because there's still a thread pool thread blocking on the web request.
For this reason, you should almost never use Task.Run (or any other method that queues work to the thread pool) on ASP.NET.
Is this suitable or should i use the Begin/End methods of HttpWebRequest too. This seems like overkill as it would be asyncing an already async operation
It's not really asynchronous right now; there's still a thread being blocked. I call this "queue blocking work to a thread pool thread and then await it" technique fake asynchrony.
The appropriate fix is to use HttpClient, which was designed for asynchronous use; or, you could use TaskFactory<T>.FromAsync to wrap the Begin/End methods into an awaitable task.
The thing i dont understand though is if i use await HttpClient.SendAsync then somewhere something must be blocking waiting for a response
No, there doesn't have to be something blocking somewhere. As I describe on my blog, in a truly asynchronous scenario (i.e., not fake-asynchrony), there is no thread.
I would recommend you to retain the async methods, and use HttpClient instead of HttpWebRequest, because it supports asynchronous calls as well.
Let's have a look at a pseudo example of a CarsController calling a third party service.
public class CarsController : ApiController
{
[Route("cars/{id}")]
public async Task<IHttpActionResult> Get(int id)
{
//Get a car by its id
HttpClient client = new HttpClient();
//Read the content directly
string result = await client.GetStringAsync("http://www.google.com");
//process the result returns from the thrid party REST service
return Ok(result);
}
}
As you can see, HttpClient supports reading String/ Stream/ ByteArray asynchronously via GetXXXAsync() methods.
If you want to access to the underlying response content, that can be achieved by using the following code:
[Route("responsecars/{id}")]
public async Task<IHttpActionResult> GetResponseStream(int id)
{
HttpClient client = new HttpClient();
HttpResponseMessage responseMessage =await client.GetAsync("http://www.google.com", HttpCompletionOption.ResponseContentRead);
HttpContent content = responseMessage.Content;
//using one of the ReadAsync methods
string text =await content.ReadAsStringAsync();
return Ok(text);
}
Hope this help.
Asynchrony on the server is separate and independent from asynchrony on the client.
You can call a synchronous Web API method asynchronously from the client with WebRequest.GetResponseAsync, or you can call an asynchronous Web API method synchronously from the client with WebRequest.GetResponse, or you can have asynchrony on both sides, which is probably the best approach. You don't need to use Begin/End APM-style WebRequest APIs, unless you target .NET 4.0 on the client. Use Task-based async APIs instead.
In either case, a complete HTTP request will be sent to the client when your Web API controller method has fully finished, regardless of whether it is implemented as synchronous or asynchronous (Task-based).

Resources