Как работает Async/Await если не создает потоки? [дубликат]

563
01 сентября 2017, 20:50

На данный вопрос уже ответили:

  • Нужен async/await или не нужен? 4 ответа

В документации написано:

Асинхронные методы используются для неблокирующих операций. Выражение await в асинхронном методе не блокирует текущий поток на время выполнения ожидаемой задачи. Вместо этого выражение регистрирует остальную часть метода как продолжение и возвращает управление вызывающему объекту асинхронного метода.

И собственно вопрос, а как достигается отзывчивость приложения?

А так же встает вопрос, если поток никаких не создается, то не создается ли иллюзия параллельной работы? Например, прыгая из контекста в контекст Async/Await не понижается ли производительность, если все крутится в 1 потоке?

Или Async/Await не создает потоки, НО выполняется в отдельном потоке из пула потоков?

Answer 1

Конструкция async/await разворачивается компилятором в конечный автомат. В конечном автомате переменные вашего метода становятся полями, чем достигается возможность запоминать состояние работы метода и продолжать его после ожидания завершения длительной операции. Async/await основан на TAP , поэтому новые потоки действительно могут и не создаваться, если в этом нет необходимости, и задача, поставленная в await может быть выполнена в текущем потоке. Это и не важно. Используя async/await вы добиваетесь не параллельного выполнения, а асинхронного. Конечный автомат умеет дождаться завершения длительных операций, выходящих за рамки вашего кода, таких как отправка запросов по сети, обращение к дисковой системе или СУБД. В этом и есть основное преимущество использования async/await.

async Task<Model> GetModel(Func<Model, bool> condition)
{
     var model = await dbContext.Models.FirstOrDefaultAsync(condition);// здесь текущий поток освобождается, и может выполнять другую работу. Работа метода возобновиться, после получения ответа от БД
     return model;
}

Также следует отметить, что нужно быть внимательными и добиваться истинной асинхронности в коде. Истинный асинхронный код должен ставить в await только те методы, которые действительно освобождают поток и дожидаются выполнения операции, после чего реагируют на это. Часто такие методы основаны на EAP. Метод FirstOrDefaultAsync - это правильный метод. Если использовать не истинную асинхронность это не даст возможности освобождать потоки в await, чем не только убьет возможность масштабирования кода, но может и сделать его менее эффективным, чем без использования async/await, поскольку возможна ситуация переключения контекстов выполнения.

async Task<Model> GetModel(Func<Model, bool> condition)
{
   var model = await Task.Run(dbContext.Models.FirstOrDefault(condition);)
   return model;

} Этот код будет работать, но асинхронности здесь не будет. Потоки освобождаться не будут. Наоборот, текущий поток должен дождаться выполнения Task, которая обращается к БД. В момент когда выполнение доходит до await выполнение прерывается и текущий поток освобождается. Но код внутри Task не является асинхронным, и он заморозит поток, пока не получит ответ от БД.

READ ALSO
Синдром ломающегося базового класса [требует правки]

Синдром ломающегося базового класса [требует правки]

Объясните "Синдром ломающегося базового класса"Интересуют конкретные примеры

436
Linq c#, особенности работы с IEnumerable&lt;T&gt;-ами

Linq c#, особенности работы с IEnumerable<T>-ами

Простите, боюсь, не получится четко сформулировать вопрос и показать пример кода

430
Awesomium многопоточность

Awesomium многопоточность

Работаю с Telegram APi от MrRound Robin и Awesomium

450
Есть ли право на запись файла?

Есть ли право на запись файла?

Есть файл, точнее - его полный путь к файлуМожно ли узнать, есть ли право на запись файла?

319