I am implementing in the controller of C# Framework 4.7.2 API a method that must be asynchronous to unblock the thread (as mentioned in this article) of a heavy process so that the service can continue to serve requests from other clients, and when that process finishes return a response.
[HttpGet]
[Route("Method")]
public async Task<HttpResponseMessage> Method()
{
HttpResponseMessage task = await Task.Run(() =>
{
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
// response.Content...
return response;
});
return task;
}
The reason I have decided to do the asynchronous method is to improve performance. Are there other possible solutions?
You are misinterpreting that guidance.
Your method is synchronous, and Task.Run is effectively mocking asynchronous behaviour by offloading the work to a Thread Pool thread.
In an ASP.Net context, that thread is coming from the pool that is used to serve other requests, so whilst you are unblocking the current thread and releasing it back to the pool, you are instead borrowing another thread to do the work.
This thread switching does not make any more threads available, but does introduce unnecessary overhead.
What is the solution?
Well, removing the call to Task.Run will introduce a slight performance improvement, but if your service does experience throughput issues you could persist the request to a queue to be picked up by another process, allowing your Method to return early and keep your API reponsive.
Considering your code execution is synchronous marking it async for the sake of it may not make a lot of sense.
However if it is a must to have async endpoint even for synchronous operations, you could use await Task.FromResult(resultObject); or its void variant await Task.CompletedTask. This would make your code like:
[HttpGet]
[Route("Method")]
public async Task<HttpResponseMessage> Method()
{
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
// response.Content...
return await Task.FromResult(response);
}
Also look at this link from MSFT for further details
Related
I don't quite understand the difference between Task.Wait and await.
I have something similar to the following functions in a ASP.NET WebAPI service:
public class TestController : ApiController
{
public static async Task<string> Foo()
{
await Task.Delay(1).ConfigureAwait(false);
return "";
}
public async static Task<string> Bar()
{
return await Foo();
}
public async static Task<string> Ros()
{
return await Bar();
}
// GET api/test
public IEnumerable<string> Get()
{
Task.WaitAll(Enumerable.Range(0, 10).Select(x => Ros()).ToArray());
return new string[] { "value1", "value2" }; // This will never execute
}
}
Where Get will deadlock.
What could cause this? Why doesn't this cause a problem when I use a blocking wait rather than await Task.Delay?
Wait and await - while similar conceptually - are actually completely different.
Wait will synchronously block until the task completes. So the current thread is literally blocked waiting for the task to complete. As a general rule, you should use "async all the way down"; that is, don't block on async code. On my blog, I go into the details of how blocking in asynchronous code causes deadlock.
await will asynchronously wait until the task completes. This means the current method is "paused" (its state is captured) and the method returns an incomplete task to its caller. Later, when the await expression completes, the remainder of the method is scheduled as a continuation.
You also mentioned a "cooperative block", by which I assume you mean a task that you're Waiting on may execute on the waiting thread. There are situations where this can happen, but it's an optimization. There are many situations where it can't happen, like if the task is for another scheduler, or if it's already started or if it's a non-code task (such as in your code example: Wait cannot execute the Delay task inline because there's no code for it).
You may find my async / await intro helpful.
Based on what I read from different sources:
An await expression does not block the thread on which it is executing. Instead, it causes the compiler to sign up the rest of the async method as a continuation on the awaited task. Control then returns to the caller of the async method. When the task completes, it invokes its continuation, and execution of the async method resumes where it left off.
To wait for a single task to complete, you can call its Task.Wait method. A call to the Wait method blocks the calling thread until the single class instance has completed execution. The parameterless Wait() method is used to wait unconditionally until a task completes. The task simulates work by calling the Thread.Sleep method to sleep for two seconds.
This article is also a good read.
Some important facts were not given in other answers:
async/await is more complex at CIL level and thus costs memory and CPU time.
Any task can be canceled if the waiting time is unacceptable.
In the case of async/await we do not have a handler for such a task to cancel it or monitoring it.
Using Task is more flexible than async/await.
Any sync functionality can by wrapped by async.
public async Task<ActionResult> DoAsync(long id)
{
return await Task.Run(() => { return DoSync(id); } );
}
async/await generate many problems. We do not know if await statement will be reached without runtime and context debugging. If first await is not reached, everything is blocked. Sometimes even when await seems to be reached, still everything is blocked:
https://github.com/dotnet/runtime/issues/36063
I do not see why I must live with the code duplication for sync and async method or using hacks.
Conclusion: Creating Tasks manually and controlling them is much better. Handler to Task gives more control. We can monitor Tasks and manage them:
https://github.com/lsmolinski/MonitoredQueueBackgroundWorkItem
Sorry for my english.
I'm comparing the performance when taking away await keyword from my method, and it's giving me over 15x better performance.
The following method performs much better:
private static async Task<HttpResponseMessage> AwaitResponse(HttpRequest proxy)
{
foreach (var header in proxy.Request.Headers)
{
Client.Instance.DefaultRequestHeaders.Add(header.Key, header.Value);
}
var response = Client.Instance.SendAsync(proxy.Request).Result;
return response;
}
than this one:
private static async Task<HttpResponseMessage> AwaitResponse(HttpRequest proxy)
{
foreach (var header in proxy.Request.Headers)
{
Client.Instance.DefaultRequestHeaders.Add(header.Key, header.Value);
}
var response = Client.Instance.SendAsync(proxy.Request);
return await response;
}
Notice How I am calling .Result in the first version of the method.
Why is this happening? Why is there such a tremendous performance penalty?
Please note that Client is simply a static instance of HttpClient.
When using await, the execution context of the code is suspended until the async method returns. By default, await attempts to restore the new thread to the incoming synchronization context that it originated in. This can sometimes have performance implications, as the CLR needs to wait for the original SynchronizationContext to marshal back.
Generally speaking, unless you have a specific need to return to the same thread context that you left (say, in a client app, to return to the UI thread), it's best to add ConfigureAwait(false) and continue on any arbitrary thread.
Given that you do not actually use the response for anything in the snippets there is no need to actually use async/await or to call .Result. You can just return the Task for the caller to await or call .Result at a higher level.
private static Task<HttpResponseMessage> AwaitResponse(HttpRequest proxy) {
foreach (var header in proxy.Request.Headers) {
Client.Instance.DefaultRequestHeaders.Add(header.Key, header.Value);
}
return Client.Instance.SendAsync(proxy.Request);
}
I would also suggest reviewing
Async/Await - Best Practices in Asynchronous Programming from Stephen Cleary
the issues around not mixing blocking and async code and also about how and when to ConfigureAwait(false) when you can
The MSDN documentation for await and async gives the following simple example.
async Task<int> AccessTheWebAsync()
{
HttpClient client = new HttpClient();
Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");
DoIndependentWork();
string urlContents = await getStringTask;
return urlContents.Length;
}
It then states:
If AccessTheWebAsync doesn't have any work that it can do between
calling GetStringAsync and awaiting its completion, you can simplify
your code by calling and awaiting in the following single statement.
string urlContents = await client.GetStringAsync();
But if there is no work to be done between calling the method and its completion what are the benefits of making this method asynchronous?
The await keyword means that the Thread starting the GetStringAsync method may become free during the execution of that method.
So for example let's say this is a web-server (e.g. with 10 threads in a thread-pool, which are responsible for processing the requests). In that case between the beginning of the GetStringAsync call and it's finish that thread is free to do other stuff.
Meaning even with 10 thread you can serve more then 10 users on a very effective way. If there would be no await in your code (and GetStringAsync would not be async, but a blocking synchronous method) and 11 users would access it at the same time then one of them would have trouble, since there would be no free thread to process the 11. request.
If that call would be a blocking synchronous code then the execution would just stay there and do nothing while your network card would just wait for the HTTP response from the server. So basically with "await" you avoid threads which are just waiting and do nothing.
When you await an async method, the thread is freed to do other work. In the synchronous version, that thread would have been blocked.
In general Async-Await consumes lesser threads, improves scalability by reducing memory/thread usage.
It also improves responsiveness as compared to synchronous code.
check Advantages of Async-Await
From my understanding when we use await and the awaited task is not yet completed then the execution returns to caller. It works fine in server side(calling the async method from server side method itself). But what happends when I call from UI to an async method.
public class TestController : ApiController
{
IList<string> lstString = new List<string>();
public async Task<IList<string>> GetMyCollectionAsync()
{
lstString.Add("First");
string secString = await GetSecondString(); // I am expecting a response back to UI from here.
lstString.Add(secString);
lstString.Add("Third");
return lstString;
}
private async Task<string> GetSecondString()
{
await Task.Delay(5000);
return "Second after await";
}
}
I tested with the above API from browser like
http://localhost:port/Test
, but I got response only after 5 sec in my UI.
Am I thinking it wrongly?
Am I thinking it wrongly?
Yes. async-await does not change the nature of the HTTP protocol, which is of type request-response. When using async-await inside an ASP.NET controller, using an async method will not yield a response to the caller, it would only yield the requests thread back to the threadpool.
But if this is true, then using async method having a single await in controller side is not useful. right? because it took the same time of synchronous call
Async shines when you need scalability. It isn't about "yield this response as fast as possible", it's about being able to handle a large amount of requests without exhausting the thread-pool. Once the thread starts executing IO work, instead of being blocked, it is returned. Thus, able to serve more requests.
Async by itself does not make anything "go faster", which is a conception I see people thinking alot. If you're not going to be hitting your web service with many concurrent requests, you're most likely not going to be seeing any benefit from using it. As #Scott points out, an async method has a slight overhead as it generates a state machine behind the scenes.
async/await allow the thread to go off servicing other requests while there is that idle 5 seconds, but ultimately everything in GetMyCollectionAsync has to complete before a response is sent to the client.
So I'd expect your code to take 5 seconds and return all 3 strings in the response.
Lets say im within an ASP.NET application, WCF or web API, part of this applications job to is contact a 3rd party over the way. Id like to do this asynchronously or rather non blocking so that the thread pool doesnt get starved. However i dont want to change all my code in the service only the bit that makes the web call.
Here is some code i have written:
public string GetSomeData()
{
Task<string> stuff = CallApiAsync();
return stuff.result; //does this block here?
}
private async Task<string> CallApiasync()
{
using (var httpClient = new HttpClient())
{
string response = await httpClient.GetStringAsync(Util.EndPoint).ConfigureAwait(false);
return response;
}
}
I thought the idea was as follows but please correct any misconceptions.
The caller of CallApi can call the method and when it hits await there is a Task created which represents some work to be done asynchronously but that will take some time. At this point the thread reaches an await returns to the thread pool to do something else ie handle a different request. Once the Task completes the await line wakes up and the code continues from there as if it was synchronous.
If this is the case why do i need to return a Task from my apimethod. The caller seems to have to call stuff.Result which implies that the task may not have finished and calling result could block ? Note i don't want to make the calling method async too as then the method that calls that would need to be async etc etc.
What is the order of event here in my code?
One other question is why did i need to set configureAwait to false? otherwise everything hangs.
Id like to do this asynchronously or rather non blocking so that the thread pool doesnt get starved. However i dont want to change all my code in the service only the bit that makes the web call.
That's not possible. In order to be truly asynchronous, you must allow async to "grow" through the code as far as it needs to. What you're trying to do is block on an asynchronous call, which won't give you any benefit (you're freeing up a thread by using async, but then you're turning around and consuming a thread by using Result).
At this point the thread reaches an await returns to the thread pool to do something else ie handle a different request.
Not quite. When an async method hits an await, it returns an incomplete Task to its caller. If the caller, in turn, awaits that task, then it returns an incomplete Task to its caller, etc. When the ASP.NET runtime receives an incomplete Task from your action/service method/whatever, then it releases the thread to the thread pool.
So, you do have to go "async all the way" to see the real benefit of async.
I have an async intro on my blog if you want a more gentle introduction, as well as an MSDN article on async best practices (one of which is: async all the way). I also have a blog post that describes the deadlock you were seeing.
The compiler handles a lot of the magic behind the async pattern for you, but syntactically, you have to tell it what you want it to do by providing a method prototype that says "ok, this is an asynchronous operation that can be awaited."
For this to happen, your method must return a Task or Task<T>.
Any Task can be awaited.
You should be VERY careful when using .Result and .Wait(), as they can block in some very unexpected circumstances, because the runtime may decide to execute your method synchronously.
You should say:
await CallApiAsync();
or, to actually take advantage of it:
Task stuff = CallApiAsync();
//More code that can happen independetly of "stuff"
await stuff;
In order to do that, your GetSomeData() function must also be marked as async, but it doesn't have to, itself, return a Task.
Finished copy of a working async version of your code:
public async string GetSomeData()
{
Task stuff = CallApiAsync();
return await stuff;
}
private async Task<string> CallApiasync()
{
using (var httpClient = new HttpClient())
{
string response = await httpClient.GetStringAsync(Util.EndPoint).ConfigureAwait(false);
return response;
}
}
Honestly, if that's all the CallApiAsync function is ever going to do, you may as well inline it, though.