Связаны ли async / await с дополнительными затратами при досрочном возврате из метода? - PullRequest
2 голосов
/ 25 мая 2020

Связаны ли async / await с дополнительными затратами при раннем возврате из метода по сравнению с синхронным методом?

Возьмите следующие примеры:

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;
}

Я знаю, что async / await имеет это связано с дополнительными затратами, и поэтому вам нужно быть осторожным с жесткими петлями - см. например, https://www.red-gate.com/simple-talk/dotnet/net-framework/the-overhead-of-asyncawait-in-net-4-5/

Но когда возникают эти затраты?

  • Это когда вы помечаете метод как asyn c?
  • Это когда ему нужно ждать?
  • Или это связано с возвратом задачи type?
  • Особенно: происходит ли падение производительности при раннем возврате для асинхронного c метода?

В конце концов, всегда лучше профилировать конкретные c случаев, но меня интересует теория, лежащая в основе этого.

Ответы [ 2 ]

4 голосов
/ 25 мая 2020

Код в вашем TryDoSomethingAsync преобразуется компилятором в код IL, который более или менее эквивалентен этому:

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);
    }
}

Выполняется значительно больше кода, чем простой asyn c method.

Однако код, который запускает Is99PercentOfTheCases(), по-прежнему довольно легкий. Это будет быстро, но не так быстро, как неасинхронный метод c.

0 голосов
/ 25 мая 2020

Изменение сигнатуры метода только на async Task не включает никаких затрат на производительность, так как это только enables функция ожидания (asyn c включает ожидание внутреннего метода и таблицы задач, ожидающих такой метод извне). Таким образом, оба ваших метода при возврате false имеют одинаковое влияние на производительность.

...