Replace async method with sync version - drawbacks? - c#

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.

Related

await in async task method with synchronous logic c#

I've a stupid question to ask everyone to learn some best practises async return types in c#. I've a method like this:
public virtual async Task OnConnected(WebSocket socket, HttpContext context)
{
string connectionId = CreateConnectionId(context);
ConnectionManager.AddSocket(connectionId, socket);
//Question is here await what ?
}
I'd like to post to improve my application with a best performance with async and await. Pls don't thumb dowm my post. Can everyone suggest for me some resources best practices async return types?
Tks everyone.
If there is nothing to await and this is an overridden method. Just ignore the compiler warning (or pragma is out), and do nothing.
Why do nothing?
Because when you place an async on a method, the compiler automatically places any exception on the task for you.
or you could remove the async and return a completed task
public virtual Task OnConnected(WebSocket socket, HttpContext context)
{
string connectionId = CreateConnectionId(context);
ConnectionManager.AddSocket(connectionId, socket);
return Task.CompletedTask;
}
My advice would be to do the former, (do nothing)
However if you were to go the second approach it would be better to place any exceptions on the returned task just as the async and await pattern would.
public virtual Task OnConnected(WebSocket socket, HttpContext context)
{
try
{
string connectionId = CreateConnectionId(context);
ConnectionManager.AddSocket(connectionId, socket);
// more stuff
return Task.CompletedTask;
}
catch (Exception e)
{
return Task.FromException(e);
}
}
learn some best practises async return types in c#.
The first rule of async is "don't use it unless you need to." The second rule is "start with await, not async".
So this part of the question is incorrect:
//Question is here await what ?
Instead of starting with async and trying to "make the code asynchronous", you should start at the opposite end: identify what is naturally asynchronous (i.e., what you should await) first. You need something to await before making your code asynchronous.
You should use await if you have naturally-asynchronous work to do. This is usually I/O-based, so if you're calling an API or doing a database query, that would be something that can be made asynchronous. Once you identified the low-level I/O call, change the method to call the asynchronous version of that API, and add an await. The compiler will guide you from there, changing the method containing the await to be async and changing its return type from void to Task or T to Task<T>. Then let async/await grow naturally through your codebase.
If you do not have any asynchronous operation to be waited for, then you can make the method as a normal synchronous method. If you are making a method async, then it is good practice to name the method in such a way that it ends with ASYNC like OnConnectedAsync.
Generally you use async/await methods when you have any I/O operations (like file access, web download/upload) that can be done independent of your program logic. Simply put the control flow goes like,
main thread calls the async method to trigger the I/O operation
control is returned to main thread after an await is encountered; usually another thread is allotted to execute remaining statements of the async method
main thread continues to execute its statements until it requires the result of the I/O operation
main thread waits for the result of async method (i.e. result of I/O operation) by calling any wait or GetResult method of Task
once the main thread gets the results, it continues executing its statements
You can go through numerous tutorial videos on youtube on async/await.

Why do i need to use ConfigureAwait(false) in all of transitive closure?

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.

Async taking 15x longer than sync

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

Should I add the async modifier if I return a Task in an expensive method?

The C# compiler already warns us if we have a method that has the async modifier but does not use the await operator.
According to this answer there's no point adding an await to the end of an async method (and in that case, just remove the async modifier).
But what if the method has an expensive synchronous operation it needs to perform before calling a subsequent true async method?
For example, if I'm using HttpClient:
private readonly HttpClient client = ...
public Task<HttpResponseMessage> CallMyWebServiceMethod() {
HttpRequestMessage request = this.SomeExpensiveButSynchronousMethod();
return this.client.SendAsync( request );
}
This code would block the caller (due to SomeExpensiveButSynchronousMethod).
However, if I change the code to this:
public async Task<HttpResponseMessage> CallMyWebServiceMethod() {
HttpRequestMessage request = this.SomeExpensiveButSynchronousMethod();
return await this.client.SendAsync( request );
}
and I call it like so:
HttpResponse response = await myWrapper.CallMyWebServiceMethod();
...I understand the TPL would spin up a background thread immediately and then run CallMyWebServiceMethod in the background thread, resuming whatever the parent code wants, making the entire call non-blocking in the process, before resuming after the Task completes and returns the HttpResponse.
...if that's the case then it seems contradictory.
If I'm wrong, and the call is blocking until it gets to SendAsync then how can I execute SomeExpensiveButSynchronousMethod on the same background thread as the HttpClient uses for its request?
According to this answer there's no point adding an await to the end of an async method (and in that case, just remove the async modifier).
That's an oversimplification. See my blog post on eliding async and await.
But what if the method has an expensive synchronous operation it needs to perform before calling a subsequent true async method?
This is a rare case, but the appropriate solution IMO is to execute the synchronous operation synchronously (i.e., not wrapped in a Task.Run) and be sure to document its behavior.
I understand the TPL would spin up a background thread immediately and then run CallMyWebServiceMethod in the background thread, resuming whatever the parent code wants, making the entire call non-blocking in the process, before resuming after the Task completes and returns the HttpResponse.
That is not at all what happens. You may find my async intro helpful. Quote:
The beginning of an async method is executed just like any other method. That is, it runs synchronously until it hits an “await” (or throws an exception).
In actuality, both of your examples synchronously block the caller while executing SomeExpensiveButSynchronousMethod.
If I'm wrong, and the call is blocking until it gets to SendAsync then how can I execute SomeExpensiveButSynchronousMethod on the same background thread as the HttpClient uses for its request?
HttpClient doesn't use a background thread for its request, so this part of the question doesn't make sense. For more information on how asynchronous I/O works, see my blog post There Is No Thread.
To answer the actual question:
Should I add the async modifier if I return a Task in an expensive method?
Yes. But the reason you should do so is not to "make it asynchronous"; it's so that any exceptions from SomeExpensiveButSynchronousMethod are captured and placed on the returned Task, which is the expected semantic for methods that follow the Task-based Asynchronous Pattern (TAP).
I understand the TPL would spin up a background thread immediately and then run CallMyWebServiceMethod
No, that's not what happens. The first synchronous part of an async method executes synchronously. If you want make sure it does not block the current thread, you should use Task.Run().
Your expensive method is going to block the caller either way. async doesn't magically create threads for you, that's what Task does (sometimes). So, if you add async and await the SendAsync, you're just adding state-machine overhead needlessly.
see also http://blog.stephencleary.com/2016/12/eliding-async-await.html

How to do asynchronous web calls from within asp.net

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.

Categories

Resources