问题
Does async/await have an extra cost associated when returning early from the method compared to the synchronous method?
Take these examples:
public async Task<bool> TryDoSomethingAsync()
{
if ( Is99PercentOfTheCases() )
return false; // does this path...
await DoSomethingAsync();
return true;
}
// versus
public bool TryDoSomething()
{
if ( Is99PercentOfTheCases() )
return false; // ...have the same cost as this path?
DoSomething();
return true;
}
I know async/await has an extra cost associated and therefore you need to be careful around tight loops - see i.e. https://www.red-gate.com/simple-talk/dotnet/net-framework/the-overhead-of-asyncawait-in-net-4-5/
But when is this cost occurring?
- Is it when you mark a method as async?
- Is it when it needs to await?
- Or is it related to the Task return type?
- Especially: does the performance hit still occur when returning early for an async method?
In the end it's always best to profile specific cases, but I'm interested in the theory behind it.
回答1:
The code in your TryDoSomethingAsync
get converted by the compiler to IL code that is, more or less, the equivalent of this:
public Task<bool> TryDoSomethingAsync()
{
TryDoSomethingAsyncStateMachine stateMachine = new TryDoSomethingAsyncStateMachine();
stateMachine._this = this;
stateMachine._builder = AsyncTaskMethodBuilder<bool>.Create();
stateMachine._state = -1;
AsyncTaskMethodBuilder<bool> _builder = stateMachine._builder;
_builder.Start(ref stateMachine);
return stateMachine._builder.Task;
}
private sealed class TryDoSomethingAsyncStateMachine : IAsyncStateMachine
{
public int _state;
public AsyncTaskMethodBuilder<bool> _builder;
public UserQuery _this;
private TaskAwaiter _awaiter;
private void MoveNext()
{
int num = _state;
bool result;
try
{
TaskAwaiter awaiter;
if (num == 0)
{
awaiter = _awaiter;
_awaiter = default(TaskAwaiter);
num = (_state = -1);
goto IL_0080;
}
if (!_this.Is99PercentOfTheCases())
{
awaiter = _this.DoSomethingAsync().GetAwaiter();
if (!awaiter.IsCompleted)
{
num = (_state = 0);
_awaiter = awaiter;
TryDoSomethingAsyncStateMachine stateMachine = this;
_builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine);
return;
}
goto IL_0080;
}
result = false;
goto end_IL_0007;
IL_0080:
awaiter.GetResult();
result = true;
end_IL_0007:;
}
catch (Exception exception)
{
_state = -2;
_builder.SetException(exception);
return;
}
_state = -2;
_builder.SetResult(result);
}
void IAsyncStateMachine.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
this.MoveNext();
}
[DebuggerHidden]
private void SetStateMachine(IAsyncStateMachine stateMachine)
{
}
void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
{
//ILSpy generated this explicit interface implementation from .override directive in SetStateMachine
this.SetStateMachine(stateMachine);
}
}
There is considerable more code that is run that the plain async method.
However, the code that runs the Is99PercentOfTheCases()
is still fairly light. It will be quick, but not as quick as the non-async method.
回答2:
Changing the method signature to async Task
only does not include any performance cost, since it only enables
await feature (async enables awaiting inside method and Task anables awaiting such a method from outside).
So both of your methods, when returning false, have the same performance impact.
来源:https://stackoverflow.com/questions/62002676/does-async-await-have-an-extra-cost-associated-when-returning-early-from-the-met