Suppose I have a C# controller that calls into some arbitrary function that returns a Task (for instance because it performs a database transaction). Should I always use async and await, or should I just return the task?
Example controller:
public async Task<string> DoSomething() { return await SomeOtherFunctionThatReturnsATask(); }
Should I change this into:
public Task<string> DoSomething() { return SomeOtherFunctionThatReturnsATask(); }
Or does it really not matter?
If a method is declared async, make sure there is an await! If your code does not have an await in its body, the compiler will generate a warning but the state machine will be created nevertheless, adding unnecessary overhead for an operation that will actually never yield.
For methods other than event handlers that don't return a value, you should return a Task instead, because an async method that returns void can't be awaited. Any caller of such a method must continue to completion without waiting for the called async method to finish.
If a method has no async operations inside it there's no benefit in making it async . You should only have async methods where you have an async operation (I/O, DB, etc.). If your application has a lot of these I/O methods and they spread throughout your code base, that's not a bad thing.
Inside an async function, you can use the await keyword before a call to a function that returns a promise. This makes the code wait at that point until the promise is settled, at which point the fulfilled value of the promise is treated as a return value, or the rejected value is thrown.
Yes, you should change the method and remove the async/await. The async
keyword causes the compiler to create a state machine that manages the 'waiting' for the task to complete. When you await another function like that, you're essentially creating two of these state machines which is unnecessary. It's much better to just return the task from the second function directly and allow the final consumer of the task to do the waiting.
The best way to understand this, is to write a small sample program and decompile it. Make sure your decompiler is showing you all the compiler generated stuff (which some hide by default) and you will be able to see what all is going on there.
Here's a quick example I just whipped up and used dotPeek to decompile:
public Task<string> DoSomething() { Class1.\u003CDoSomething\u003Ed__0 stateMachine; stateMachine.\u003C\u003E4__this = this; stateMachine.\u003C\u003Et__builder = AsyncTaskMethodBuilder<string>.Create(); stateMachine.\u003C\u003E1__state = -1; stateMachine.\u003C\u003Et__builder.Start<Class1.\u003CDoSomething\u003Ed__0>(ref stateMachine); return stateMachine.\u003C\u003Et__builder.Task; } private Task<string> DoSomethingElse() { return Task.FromResult<string>("test"); }
You can see the state machine in the first one that I was referring to. It's going to do all that work of await'ing for no reason, and then the final consumer of DoSomething()
is going to repeat that same work. Realistically you should only really use the await
keyword when there is other code in the method that needs to be run after the code that returns the task. Because that code needs to await for it to complete before it runs.
Full decompiled code here: http://pastebin.com/iJLAFdHZ
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With