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
Related
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
I am learning async/await and after I read this article Don't Block on Async Code
and this Is async/await suitable for methods that are both IO and CPU bound
I notice one Tip from #Stephen Cleary 's article.
Using ConfigureAwait(false) to avoid deadlocks is a dangerous practice. You would have to use ConfigureAwait(false) for every await in the transitive closure of all methods called by the blocking code, including all third- and second-party code. Using ConfigureAwait(false) to avoid deadlock is at best just a hack).
It appeared again in the code of the post as I have attached above.
public async Task<HtmlDocument> LoadPage(Uri address)
{
using (var httpResponse = await new HttpClient().GetAsync(address)
.ConfigureAwait(continueOnCapturedContext: false)) //IO-bound
using (var responseContent = httpResponse.Content)
using (var contentStream = await responseContent.ReadAsStreamAsync()
.ConfigureAwait(continueOnCapturedContext: false)) //IO-bound
return LoadHtmlDocument(contentStream); //CPU-bound
}
As my knowledge when we using ConfigureAwait(false) the rest of async method will be run in the thread pool. Why we need to add it into every await
in transitive closure? I myself just think this is the correct version as what I knew.
public async Task<HtmlDocument> LoadPage(Uri address)
{
using (var httpResponse = await new HttpClient().GetAsync(address)
.ConfigureAwait(continueOnCapturedContext: false)) //IO-bound
using (var responseContent = httpResponse.Content)
using (var contentStream = await responseContent.ReadAsStreamAsync()) //IO-bound
return LoadHtmlDocument(contentStream); //CPU-bound
}
It means the second use of ConfigureAwait(false) in using block is useless. Please tell me the correct way.
Thanks in advance.
As my knowledge when we using ConfigureAwait(false) the rest of async method will be run in the thread pool.
Close, but there is an important caveat you are missing. When you resume after awaiting a task with ConfigureAwait(false), you will resume on an arbitrary thread. Take note of the words "when you resume."
Let me show you something:
public async Task<string> GetValueAsync()
{
return "Cached Value";
}
public async Task Example1()
{
await this.GetValueAsync().ConfigureAwait(false);
}
Consider the await in Example1. Although you are awaiting an async method, that method does not actually perform any asynchronous work. If an async method doesn't await anything, it executes synchronously, and the awaiter never resumes because it never suspended in the first place. As this example shows, calls to ConfigureAwait(false) may be superfluous: they may have no effect at all. In this example, whatever context you were on when you enter Example1 is the context you will be on after the await.
Not quite what you expected, right? And yet, it's not altogether unusual. Many async methods may contain fast paths that don't require the caller to suspend. The availability of a cached resource is a good example (thanks, #jakub-dÄ…bek!), but there plenty of other reasons an async method might bail early. We often check for various conditions at the beginning of a method to see if we can avoid doing unnecessary work, and async methods are no different.
Let's look at another example, this time from a WPF application:
async Task DoSomethingBenignAsync()
{
await Task.Yield();
}
Task DoSomethingUnexpectedAsync()
{
var tcs = new TaskCompletionSource<string>();
Dispatcher.BeginInvoke(Action(() => tcs.SetResult("Done!")));
return tcs.Task;
}
async Task Example2()
{
await DoSomethingBenignAsync().ConfigureAwait(false);
await DoSomethingUnexpectedAsync();
}
Take a look at Example2. The first method we await always runs asynchronously. By the time we hit the second await, we know we're running on a thread pool thread, so there's no need for ConfigureAwait(false) on the second call, right? Wrong. Despite having Async in the name and returning a Task, our second method wasn't written using async and await. Instead, it performs its own scheduling and uses a TaskCompletionSource to communicate the result. When you resume from your await, you might[1] end up running on whatever thread provided the result, which in this case is WPF's dispatcher thread. Whoops.
The key takeaway here is that you often don't know exactly what an 'awaitable' method does. With or without ConfigureAwait, you might end up running somewhere unexpected. This can happen at any level of an async call stack, so the surest way to avoid inadvertently taking ownership of a single-threaded context is to use ConfigureAwait(false) with every await, i.e., throughout the transitive closure.
Of course, there may be times when you want to resume on your current context, and that's fine. That is ostensibly why it's the default behavior. But if you don't genuinely need it, then I recommend using ConfigureAwait(false) by default. This is especially true for library code. Library code can get called from anywhere, so it's best adhere to the principle of least surprise. That means not locking other threads out of your caller's context when you don't need it. Even if you use ConfigureAwait(false) everywhere in your library code, your caller will still have the option to resume on their original context if that's what they want.
[1] This behavior may vary by framework and compiler version.
I have an async method for my app which simplifies a HTTP request for my needs:
public async Task<string> MyAsyncMethod()
{
...
using (var httpResp = (HttpWebResponse)await req.GetResponseAsync().ConfigureAwait(false))
{
...
using (StreamReader reader = new StreamReader(
httpResp.GetResponseStream()))
{
return _response = await reader.ReadToEndAsync().ConfigureAwait(false);
}
}
}
Now I want to make a corresponding non-async method by reusing as much code as possible.
I was thinking of doing the following:
Rewrite method to sync method (use GetResponse and ReadToEnd instead of async methods)
Replace ResponseAsync() with a method that references the sync method
But would mean I could ditch my async method altogether and always use my sync method in an async context, which would reduce async-nesting (which is good). I mean in both cases the same operation (e.g. getting a response) is done in an async context anyway, so what is the difference?
But would mean I could ditch my async method altogether and always use
my sync method in an async context, which would reduce async-nesting
(which is good). I mean in both cases the same operation (e.g. getting
a response) is done in an async context anyway
That's incorrect. If by "use my sync method in an async context" you mean wrapping your synchronous version with Task.Run (which is the async over sync anti-pattern) then that is not the same as using a truely async method. When you use async methods, you're freeing the calling thread to do more work while the asynchronous operation is on-going. When your using a sync version, you're doing the opposite, you're blocking until that method call completes. When you wrap a blocking method with Task.Run, you're actually using another thread just to block inside it, because the delegate will be of your sync version.
Side note:
Using HttpClient can greatly reduce the amount of code you need to offload a request:
public Task<string> RequestAsync(string url)
{
var httpClient = new HttpClient();
return httpClient.GetAsStringAsync(url);
}
The difference is that async methods that return Task will return immediately, (i.e. will not wait the operation to complete unless you specify explicitly with await).
So for your case your method will not change a lot, but maybe the usage of your method will differ, because you will not need events to tell you execution is completed; the code continues when it finishes.
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.
When I use an async-await method (as the example below) in a HttpClient call, this code causes a deadlock. Replacing the async-await method with a t.ContinueWith, it works properly. Why?
public class MyFilter: ActionFilterAttribute {
public override void OnActionExecuting(ActionExecutingContext filterContext) {
var user = _authService.GetUserAsync(username).Result;
}
}
public class AuthService: IAuthService {
public async Task<User> GetUserAsync (string username) {
var jsonUsr = await _httpClientWrp.GetStringAsync(url).ConfigureAwait(false);
return await JsonConvert.DeserializeObjectAsync<User>(jsonUsr);
}
}
This works:
public class HttpClientWrapper : IHttpClient {
public Task<string> GetStringAsync(string url) {
return _client.GetStringAsync(url).ContinueWith(t => {
_log.InfoFormat("Response: {0}", url);
return t.Result;
});
}
This code will deadlock:
public class HttpClientWrapper : IHttpClient {
public async Task<string> GetStringAsync(string url) {
string result = await _client.GetStringAsync(url);
_log.InfoFormat("Response: {0}", url);
return result;
}
}
I describe this deadlock behavior on my blog and in a recent MSDN article.
await will by default schedule its continuation to run inside the current SynchronizationContext, or (if there is no SynchronizationContext) the current TaskScheduler. (Which in this case is the ASP.NET request SynchronizationContext).
The ASP.NET SynchronizationContext represents the request context, and ASP.NET only allows one thread in that context at a time.
So, when the HTTP request completes, it attempts to enter the SynchronizationContext to run InfoFormat. However, there is already a thread in the SynchronizationContext - the one blocked on Result (waiting for the async method to complete).
On the other hand, the default behavior for ContinueWith by default will schedule its continuation to the current TaskScheduler (which in this case is the thread pool TaskScheduler).
As others have noted, it's best to use await "all the way", i.e., don't block on async code. Unfortunately, that's not an option in this case since MVC does not support asynchronous action filters (as a side note, please vote for this support here).
So, your options are to use ConfigureAwait(false) or to just use synchronous methods. In this case, I recommend synchronous methods. ConfigureAwait(false) only works if the Task it's applied to has not already completed, so I recommend that once you use ConfigureAwait(false), you should use it for every await in the method after that point (and in this case, in each method in the call stack). If ConfigureAwait(false) is being used for efficiency reasons, then that's fine (because it's technically optional). In this case, ConfigureAwait(false) would be necessary for correctness reasons, so IMO it creates a maintenance burden. Synchronous methods would be clearer.
An explanation on why your await deadlocks
Your first line:
var user = _authService.GetUserAsync(username).Result;
blocks that thread and the current context while it waits for the result of GetUserAsync.
When using await it attempts to run any remaining statements back on the original context after the task being waited on finishes, which causes deadlocks if the original context is blocked (which is is because of the .Result). It looks like you attempted to preempt this problem by using .ConfigureAwait(false) in GetUserAsync, however by the time that that await is in effect it's too late because another await is encountered first. The actual execution path looks like this:
_authService.GetUserAsync(username)
_httpClientWrp.GetStringAsync(url) // not actually awaiting yet (it needs a result before it can be awaited)
await _client.GetStringAsync(url) // here's the first await that takes effect
When _client.GetStringAsync finishes, the rest of the code can't continue on the original context because that context is blocked.
Why ContinueWith behaves differently
ContinueWith doesn't try to run the other block on the original context (unless you tell it to with an additional parameter) and thus does not suffer from this problem.
This is the difference in behavior that you noticed.
A solution with async
If you still want to use async instead of ContinueWith, you can add the .ConfigureAwait(false) to the first encountered async:
string result = await _client.GetStringAsync(url).ConfigureAwait(false);
which as you most likely already know, tells await not to try to run the remaining code on the original context.
Note for the future
Whenever possible, attempt to not use blocking methods when using async/await. See Preventing a deadlock when calling an async method without using await for avoiding this in the future.
Granted, my answer is only partial, but I'll go ahead with it anyway.
Your Task.ContinueWith(...) call does not specify the scheduler, therefore TaskScheduler.Current will be used - whatever that is at the time. Your await snippet, however, will run on the captured context when the awaited task completes, so the two bits of code may or may not produce similar behaviour - depending on the value of TaskScheduler.Current.
If, say, your first snippet is called from the UI code directly (in which case TaskScheduler.Current == TaskScheduler.Default, the continuation (logging code) will execute on the default TaskScheduler - that is, on the thread pool.
In the second snippet, however, the continuation (logging) will actually run on the UI thread regardless of whether you use ConfigureAwait(false) on the task returned by GetStringAsync, or not. ConfigureAwait(false) will only affect the execution of the code after the call to GetStringAsync is awaited.
Here's something else to illustrate this:
private async void Form1_Load(object sender, EventArgs e)
{
await this.Blah().ConfigureAwait(false);
// InvalidOperationException here.
this.Text = "Oh noes, I'm no longer on the UI thread.";
}
private async Task Blah()
{
await Task.Delay(1000);
this.Text = "Hi, I'm on the UI thread.";
}
The given code sets the Text within Blah() just fine, but it throws a cross-threading exception inside the continuation in the Load handler.
I found the other solutions posted here did not work for me on ASP .NET MVC 5, which still uses synchronous Action Filters. The posted solutions don't guarantee a new thread will be used, they just specify that the same thread does not HAVE to be used.
My solution is to use Task.Factory.StartNew() and specifying TaskCreationOptions.LongRunning in the method call. This ensures a new/different thread is always used, so you can be assured you will never get a deadlock.
So, using the OP example, the following is the solution that works for me:
public class MyFilter: ActionFilterAttribute {
public override void OnActionExecuting(ActionExecutingContext filterContext) {
// var user = _authService.GetUserAsync(username).Result;
// Guarantees a new/different thread will be used to make the enclosed action
// avoiding deadlocking the calling thread
var user = Task.Factory.StartNew(
() => _authService.GetUserAsync(username).Result,
TaskCreationOptions.LongRunning).Result;
}
}