Подтвердить что ты не робот

Должен ли я использовать async/wait для каждого метода, который возвращает задачу

Предположим, что у меня есть контроллер С#, который вызывает некоторую произвольную функцию, которая возвращает задачу (например, потому что она выполняет транзакцию базы данных). Должен ли я всегда использовать async и ждать, или я должен просто вернуть задачу?

Пример контроллера:

public async Task<string> DoSomething() {
    return await SomeOtherFunctionThatReturnsATask();
}

Должен ли я изменить это на:

public Task<string> DoSomething() {
    return SomeOtherFunctionThatReturnsATask();
}

Или это действительно не имеет значения?

4b9b3361

Ответ 1

Да, вы должны изменить метод и удалить async/wait. Ключевое слово async заставляет компилятор создать конечный автомат, который управляет ожиданием завершения задачи. Когда вы ждете еще одну такую ​​функцию, вы по существу создаете две из этих состояний, которые не нужны. Гораздо лучше просто вернуть задачу из второй функции напрямую и позволить конечному потребителю задачи выполнить ожидание.

Лучший способ понять это - написать небольшую пробную программу и декомпилировать ее. Убедитесь, что ваш декомпилятор показывает вам все созданные компилятором вещи (которые некоторые скрывают по умолчанию), и вы сможете увидеть, что там происходит.

Вот быстрый пример, который я просто взбивал и использовал dotPeek для декомпиляции:

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

Вы можете видеть конечный автомат в первом, о котором я говорил. Он собирается делать всю эту работу без причины, а затем конечный потребитель DoSomething() собирается повторить ту же работу. Реально, вы действительно должны использовать только ключевое слово await, если в методе, который должен быть запущен после, другой код, который возвращает задачу. Потому что этот код должен дождаться завершения, прежде чем он запустится.

Полный декомпилированный код здесь: http://pastebin.com/iJLAFdHZ