will async Rest API call with threads affect performance? - c#

So one of my colleagues was saying to me -
"Why would somebody want to call async RestAPIs with thread, Its not beneficial and in return it will create a separate thread for every request."
My scenario is-
public async Task<ApiResponse<ProductLookupDto>> GetProductsByValueOfTheDay()
{
string url = "http://domain.com?param=10120&isBasic=true"
var result = Task.Run(() => JsonConvert.DeserializeObject<ProductLookupDto>(SerializedResults.GET(url)));
return new ApiResponse<ProductLookupDto>()
{
Data = await result,
Message = "success"
};
}
So here I am using async with threading. I know it will create a separate thread for request. Which is my concern about the performance.
I want to know if some of my methods are called together and if reponse is async as I am doing now. Will the thread affect to performance?
keeping in mind where - response from rest call is too large.

Your friend actually is not really knowing what he talks about - a Task will NOT create a separate thread for every request. Rather the task scheduler will determine threads - and the standard uses the thread pool. Which means that threads are pre allocated and reused, especially if you schedule a LOT of tasks. Also threads are released while the request runs due to completion ports. Your colleague shows a serious lack of basics here.

I think your colleague is right to be concerned with that code, and you are right to say "it pretends to be async but not really". And Jon Skeet is right to point out that the real problem here lies with SerializedResults.GET. Whatever the implentation of that is exactly, it's clearly a blocking call, otherwise it would return a Task<string> (that can be awaited) instead of a string. Wrapping a synchronous call in Task.Run and calling it asynchronous is a common mistake. You haven't eliminated blocking at all, you've simply moved the blocking call to a different thread.
So to make this asynchronous, SerializedResults.GET needs to go. It should be replaced by a call that uses a truly asynchronous library like HttpClient. Since this is a JSON API (and I'm a little bit biased), I'll show you an example using my Flurl library, which is basically a wrapper around HttpClient and Json.NET that provides some convenience methods to cut down on the noise a bit:
public async Task<ApiResponse<ProductLookupDto>> GetProductsByValueOfTheDay()
{
string url = "http://domain.com?param=10120&isBasic=true";
var result = await url.GetJsonAsync<ProductLookupDto>();
return new ApiResponse<ProductLookupDto>()
{
Data = result,
Message = "success"
};
}

Related

async await calling long running sync AND async methods

I am using asp.net web api 2 and Entity Framework 6.
Original pseudo code
public IHttpActionResult GetProductLabel(int productId)
{
var productDetails = repository.GetProductDetails(productId);
var label = labelCalculator.Render(productDetails);
return Ok(label);
}
Modified code
public async Task<IHttpActionResult> GetProductLabel(int productId)
{
var productDetails = await repository.GetProductDetailsAsync(productId); // 1 long second as this call goes into sub services
var label = labelCalculator.Render(productDetails); // 1.5 seconds synchrounous code
return Ok(label);
}
Before my change everything ran synchronously.
After my change the call to a remote service which is calling again a database is done the async-await way.
Then I do a sync call to a rendering library which offers only sync methods. The calculation takes 1,5 seconds.
Is there still a benefit that I did the remote database_service call the async-await way but the 2nd call not? And is there anything I could still improve?
Note
The reason why I ask this is because:
"With async controllers when a process is waiting for I/O to complete, its thread is freed up for the server to use for processing other requests."
So when the first remote database_service call is processing and awaiting for that 1 second the thread is returned to IIS??!!
But what about the 2nd label calculation taking 1,5 seconds that will block the current thread again for 1,5 seconds ?
So I release and block the thread, that does not make sense or what do you think?
The rendering library is not simply "blocking a thread", it is doing work performing your rendering. There is nothing better you can do.
Is there still a benefit that I did the remote database_service call
the async-await way but the 2nd call not?
Yes, this call is now non-blocking and can run alongside other code, even though it is only for 1 second.
And is there anything I could still improve?
If you can have the second call run asynchronously too, the whole method can run asynchronously and won't block at all.
Asynchronous code creates a certain continuation under the hood, it is a sort of synthetic sugar to make asynchronous programming feel more synchonious.
In general, depending on the operations themselves, it could help to make both long running tasks asynchronous. It would use different tasks under the hood for each different long running task and run them asynchronously.
At the moment, these tasks run completely synchoniously within GetProductLabel, meaning that if it is the only method you are calling you would not tell th difference between synchonious code.
If it is possible I would make the second method async, since I am not familiar with any sagnificant drawbacks of using tasks and async await.
In your case there is nothing better you can do, and it won't make much difference, since you have to run it synchronously, as you are using the result from the first method.

Double await operations during POST

Using c# HttpClient to POST data, hypothetically I'm also concerned with the returned content. I'm optimizing my app and trying to understand the performance impact of two await calls in the same method. The question popped up from the following code snippet,
public static async Task<string> AsyncRequest(string URL, string data = null)
{
using (var client = new HttpClient())
{
var post = await client.PostAsync(URL, new StringContent(data, Encoding.UTF8, "application/json")).ConfigureAwait(false);
post.EnsureSuccessStatusCode();
var response = await post.Content.ReadAsStringAsync();
return response;
}
}
Assume I have error handling in there :)
I know await calls are expensive so the double await caught my attention.
After the first await completes the POST response is in memory would it be more efficient to return the result directly, like var response = post.Content.ReadAsStringAsync().Result;
What are the performance considerations when making two await/async calls in the same method?
Will the above code result in a thread per await (2 threads), or 1 thread for the returned Task that will handle both await calls?
I know await calls are expensive so the double await caught my
attention.
Why would you say they're expensive? The compiler generated state-machine is a highly optimized beast which makes sure it doesn't bloat memory. Down to the specifics, for example, where TaskAwaiter returned from Task is a struct and not a class so it won't get allocated on the heap. As #usr points out, and is very well right, is that sending a request over-the-wire will make any state-machine allocation cost neglectable.
would it be more efficient to return the result directly, like var response
= post.Content.ReadAsStringAsync().Result;
Marking your method async is enough for the compiler to generate a state machine. The stack variables will already be lifted to the state-machine created. Once your first await is hit, the rest of your code turns into a continuation anyway. Using post.Content.ReadAsStringAsync().Result; is more likely to cause to deadlock your code rather then save you any memory consumption or make your code a micro-millisecond faster.
What are the performance considerations when making two await/async
calls in the same method?
What you should be asking yourself from a performance perspective is this - Is concurrency going to be an issue within my application which makes it worth using asynchronous operations?
async shines in places where a large amount of consumers will hitting you, and you want to make sure you have enough available resources to process those requests. I see people ask many times "why isn't this async code making my code go faster?". It won't make any noticeable change unless you are going to be under heavy traffic, heavy enough that for example, you'll be stressing out your IIS thread-pool where it will actually benefit from asynchrony.
Will the above code result in a thread per await (2 threads), or 1
thread for the returned Task that will handle both await calls?
Depends on your environment. When your first await is hit, you explicitly tell it not to marshal any synchronization context with ConfigureAwait(false). If you're running this from a UI thread, for example, then any code after PostAsync will be running on a thread-pool worker thread. Again, this shouldn't be a concern to you, these are micro-optimizations which you won't be seeing any benefit from.

Task.Run vs. direct async call for starting long-running async methods

Several times, I have found myself writing long-running async methods for things like polling loops. These methods might look something like this:
private async Task PollLoop()
{
while (this.KeepPolling)
{
var response = await someHttpClient.GetAsync(...).ConfigureAwait(false);
var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
// do something with content
await Task.Delay(timeBetweenPolls).ConfigureAwait(false);
}
}
The goal of using async for this purpose is that we don't need a dedicated polling thread and yet the logic is (to me) easier to understand than using something like a timer directly (also, no need to worry about reentrance).
My question is, what is the preferred method for launching such a loop from a synchronous context? I can think of at least 2 approaches:
var pollingTask = Task.Run(async () => await this.PollLoop());
// or
var pollingTask = this.PollLoop();
In either case, I can respond to exceptions using ContinueWith(). My main understanding of the difference between these two methods is that the first will initially start looping on a thread-pool thread, whereas the second will run on the current thread until the first await. Is this true? Are there other things to consider or better approaches to try?
My main understanding of the difference between these two methods is
that the first will initially start looping on a thread-pool thread,
whereas the second will run on the current thread until the first
await. Is this true?
Yes. An async method returns its task to its caller on the first await of an awaitable that is not already completed.
By convention most async methods return very quickly. Yours does as well because await someHttpClient.GetAsync will be reached very quickly.
There is no point in moving the beginning of this async method onto the thread-pool. It adds overhead and saves almost no latency. It certainly does not help throughput or scaling behavior.
Using an async lambda here (Task.Run(async () => await this.PollLoop())) is especially useless. It just wraps the task returned by PollLoop with another layer of tasks. it would be better to say Task.Run(() => this.PollLoop()).
My main understanding of the difference between these two methods is that the first will initially start looping on a thread-pool thread, whereas the second will run on the current thread until the first await. Is this true?
Yes, that's true.
In your scenario, there seem to be no need for using Task.Run though, there's practically no code between the method call and the first await, and so PollLoop() will return almost immediately. Needlessly wrapping a task in another task only makes the code less readable and adds overhead. I would rather use the second approach.
Regarding other considerations (e.g. exception handling), I think the two approaches are equivalent.
The goal of using async for this purpose is that we don't need a dedicated polling thread and yet the logic is (to me) easier to understand than using something like a timer directly
As a side-note, this is more or less what a timer would do anyway. In fact Task.Delay is implemented using a timer!

Easiest way to make controller asynchronous

I inherited a large web application that uses MVC5 and C#. Some of our controllers make several slow database calls and I want to make them asynchronous in an effort to allow the worker threads to service other requests while waiting for the database calls to complete. I want to do this with the least amount of refactoring. Say I have the following controller
public string JsonData()
{
var a = this.servicelayer.getA();
var b = this.servicelayer.getB();
return SerializeObject(new {a, b});
}
I have made the two expensive calls a, b asynchronous by leaving the service layer unchanged and rewriting the controller as
public async Task<string> JsonData()
{
var task1 = Task<something>.Run(() => this.servicelayer.getA());
var task2 = Task<somethingelse>.Run(() => this.servicelayer.getB());
await Task.WhenAll(task1, task2);
var a = await task1;
var b = await task2;
return SerializeObject(new {a, b});
}
The above code runs without any issues but I can't tell using Visual Studio if the worker threads are now available to service other requests or if using Task.Run() in a asp.net controller doesn't do what I think it does. Can anyone comment on the correctness of my code and if it can be improved in any way? Also, I read that using async in a controller has additional overhead and should be used only for long running code. What is the minimum criteria that I can use to decide if the controller needs async? I understand that every use case is different but wondering if there is a baseline that I can use as a starting point. 2 database calls? anything over 2 seconds to return?
The guideline is that you should use async whenever you have I/O. I.e., a database. The overhead is miniscule compared to any kind of I/O.
That said, blocking a thread pool thread via Task.Run is what I call "fake asynchrony". It's exactly what you don't want to do on ASP.NET.
Instead, start at your "lowest-level" code and make that truly asynchronous. E.g., EF6 supports asynchronous database queries. Then let the async code grow naturally from there towards your controller.
The only improvement the new code has is it runs both A and B concurrently and not one at a time. There's actually no real asynchrony in this code.
When you use Task.Run you are offloading work to be done on another thread, so basically you start 2 threads and release the current thread while awaiting both tasks (each of them running completely synchronously)
That means that the operation will finish faster (because of the parallelism) but will be using twice the threads and so will be less scalable.
What you do want to do is make sure all your operations are truly asynchronous. That will mean having a servicelayer.getAAsync() and servicelayer.getBAsync() so you could truly release the threads while IO is being processed:
public async Task<string> JsonData()
{
return SerializeObject(new {await servicelayer.getAAsync(), await servicelayer.getBAsync()});
}
If you can't make sure your actual IO operations are truly async, it would be better to keep the old code.
More on why to avoid Task.Run: Task.Run Etiquette Examples: Don't Use Task.Run in the Implementation

Wait() causes UI thread to hang - when should Wait() be used?

I have the following code that connects to a SignalR Hub
private static async Task StartListening()
{
try
{
var hubConnection = new HubConnection("http://localhost:8080/");
IHubProxy hubProxy = hubConnection.CreateHubProxy("Broadcaster");
hubProxy.On<EventData>("notifyCardAccessEvent", eventData =>
{
Log.Info(string.Format("Incoming data: {0} {1}", eventData.Id, eventData.DateTime));
});
ServicePointManager.DefaultConnectionLimit = 10;
await hubConnection.Start();
Log.Info("Connected");
}
catch (Exception ex)
{
Log.Error(ex);
}
}
In my Form_Load method, I have this
StartListening();
However, Resharper prompts me to "consider applying the 'await' operator to the result of the call"
So I did this:
Log.Info("Connecting to SignalR hub...");
StartListening().Wait();
Log.Info("Connected!");
However, this causes my UI thread to hang and Connected! is never printed to the log file.
So my question is, when should I use Wait()? What are the instances and scenarios that I should use Wait(), and when should I not use Wait()?
await is not Wait. It is unclear what the code is that is calling StartListening(), but one option is to await it, as suggested:
await StartListening();
However, in some other cases it may be better to do nothing at all:
StartListening(); // drop the Task on the floor
or perhaps use ContinueWith for a manual continuation. Since the StartListening method catches any exceptions, there isn't anything wrong with just ignoring the returned Task - so what you had already. I would suggest calling it StartListeningAsync, though.
The reason for the deadlock is that if you use Wait, your UI thread blocks waiting on an asynchronous method to complete, but that asynchronous method is capturing the sync-context, which means in order to process each continuation it tries to get onto the UI thread - which is blocked... on it.
#MarcGravell has the correct answer; I'm just going to answer this other question:
So my question is, when should I use Wait()? What are the instances and scenarios that I should use Wait(), and when should I not use Wait()?
The confusion is coming from the fact that the Task type is used for two almost completely different things.
Task was originally introduced in .NET 4.0 as part of the Task Parallel Library. Normally, you would use Parallel LINQ or the Parallel class for parallel processing (which used the Task type underneath). However, in advanced scenarios, you could use the Task type directly. Task.Wait was used to wait for those independent tasks to complete.
When async/await were introduced in .NET 4.5, the existing Task type was almost good enough to be used as an abstract "future". So instead of inventing some new "future" type, they just slightly extended Task to work as a future.
This brings us to today, where Task can be used as either:
An item of work in a parallel computation.
An asynchronous future.
(There's a tiny bit of crossover: you can treat parallel work as asynchronous, and in rare situations like Console Main methods you do need to block on asynchronous tasks; but ignore those for the moment.)
This means that the API for Task is split along those lines. Members such as Start, Wait, Result, and ContinueWith belong pretty firmly on the parallel side. In the asynchronous world, await is more appropriate.
I have a small table at the bottom of my async intro that has some new (asynchronous) equivalents for the old (parallel) ways of doing things.
You seem to misunderstand the message from Resharper. Instead of applying the await operator, you called the Task.Wait() Method. They may seem similar, but they're working completely different.
This nice answer will provide more information about the differences: https://stackoverflow.com/a/13140963/3465395

Categories