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;
}
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);
}
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);
}
}
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();
}
}
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!
Top comments (0)