Встречается на 90% собеседований по C#

Что такое Async/Await

Async/Await — это синтаксическая конструкция в C#, которая позволяет писать асинхронный код, не блокируя поток выполнения. Она основана на классе Task и предоставляет удобный способ ожидания завершения длительных операций (например, обращений к базе данных, HTTP-запросам, работе с файлами) без блокировки текущего потока.

Как это работает

Ключевое слово async помечает метод как асинхронный. Однако само по себе оно не делает метод асинхронным — важно, что внутри такого метода используется await. Когда компилятор встречает await, он преобразует метод в конечный автомат: выполнение метода приостанавливается в точке await, а управление возвращается вызывающему коду. Поток, который выполнял метод, освобождается и может заниматься другими задачами. Когда ожидаемая операция завершается, выполнение метода возобновляется с того места, где было прервано.

Пример:

csharp
public async Task<string> GetDataAsync()
{
    // Асинхронный вызов к внешнему ресурсу
    string result = await httpClient.GetStringAsync("https://example.com");
    // Выполнение продолжится после получения результата
    return result;
}

В этом примере await приостанавливает выполнение GetDataAsync, пока GetStringAsync не завершится. Поток, вызвавший этот метод, не блокируется и может обрабатывать другие события, например, обновлять интерфейс.

Подводные камни

  • async без await: если метод помечен async, но не содержит await, компилятор выдаст предупреждение. Такой метод выполняется синхронно, и его использование бессмысленно.
  • Блокировка в асинхронном методе: вызов синхронных методов (например, .Result или .Wait()) внутри асинхронного метода может привести к взаимоблокировке (deadlock), особенно в UI-приложениях с контекстом синхронизации.
  • Исключения: исключения, возникшие в асинхронном методе, сохраняются в Task и выбрасываются при ожидании через await. Если не ожидать задачу, исключение может быть потеряно.
  • Контекст синхронизации: в UI-приложениях await по умолчанию возвращает выполнение в исходный контекст (например, в поток UI). Это удобно, но может вызвать проблемы при длительных операциях, если не использовать ConfigureAwait(false).

Когда использовать

Async/Await следует применять для операций, которые реально выполняются асинхронно: ввод-вывод, сетевые запросы, работа с базами данных. Для CPU-интенсивных вычислений лучше использовать Task.Run или параллельные библиотеки, так как async не создаёт новый поток, а лишь освобождает текущий.

Коротко

  • async помечает метод, await — точку приостановки ожидания.
  • await не блокирует поток, а освобождает его для других задач.
  • Не используйте async без await — это ошибка.
  • Избегайте синхронных блокировок внутри асинхронных методов.
  • Применяйте для операций ввода-вывода, а не для CPU-интенсивных задач.
как отвечать на вопрос
пример собеседования
фреймворки на собеседовании
типичные вопросы junior
интервью вопросы и ответы