Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?
like image 770
FalacyNine Avatar asked Jun 29 '15 17:06

FalacyNine


1 Answers

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.

like image 122
Yuval Itzchakov Avatar answered Sep 19 '22 13:09

Yuval Itzchakov