DEV Community

Mikolaj Kaminski
Mikolaj Kaminski

Posted on • Originally published at mikolaj-kaminski.com

Do we have to await every single C# async method?

Did you ever see code a like that? The method calls another asynchronous method and returns its direct result.

[HttpPost]
public async Task<GetUserQueryResult> Get([FromBody] GetUserQuery query)
{
    var result = await _mediatr.Send(query);
    return result;
}
Enter fullscreen mode Exit fullscreen mode

Okay, it works perfectly well, so what's the matter? Now take a look at the code below:

[HttpPost]
public Task<GetUserQueryResult> Get([FromBody] GetUserQuery id)
{
    return _mediatr.Send(query);
}
Enter fullscreen mode Exit fullscreen mode

I got rid of the async and await keywords. This makes the Get method synchronous. It just passes the task on and does not wait for the result.

Both pieces of code work the same, but are they equally efficient? Let's check it out!

So what's the difference?

The await keyword is syntactic sugar. In fact, when compiled, it is turned into a state machine that manages the asynchronous code. Additional code increases execution time and consumes additional resources.

Let me show you an example class:

public class TestClass
{
    public Task<int> MethodA()
    {
        return Task.FromResult(1);
    }

    public async Task<int> MethodB()
    {
        return await Task.FromResult(1);
    }
}
Enter fullscreen mode Exit fullscreen mode

And its benchmark:

public class Benchmark
{
    private TestClass testObject = new TestClass();

    [Benchmark]
    public async Task NoRedundantOperators()
    {
        await testObject.MethodA();
    }

    [Benchmark(Baseline = true)]
    public async Task RedundantOperators()
    {
        await testObject.MethodB();
    }
}
Enter fullscreen mode Exit fullscreen mode

Here are the results of the benchmark:

Method Mean Error StdDev Ratio
NoRedundantOperators 34.90 ns 0.738 ns 1.035 ns 0.58
RedundantOperators 60.17 ns 1.243 ns 2.144 ns 1.00

As you can see, the code without unnecessary operators is almost twice as fast!

I have put all the benchmark code in my GitHub repository so you can test it yourself. You can find the repository here.

Finally

I hope I convince you that it is not always worth it to await every single async method call. As always, if you have any interesting thoughts on this topic, please let me know!

Discussion (0)