Что происходит, когда метод, помеченный async, встречает оператор await в C#?

«Что происходит, когда метод, помеченный async, встречает оператор await в C#?» — вопрос из категории C# Core, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

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

Что происходит под капотом:

  1. Среда выполнения (runtime) проверяет, завершена ли ожидаемая задача (Task).
  2. Если задача уже завершена, метод продолжает выполнение синхронно в том же потоке.
  3. Если задача еще выполняется, метод приостанавливается. Состояние метода (локальные переменные, позиция в коде) сохраняется в объекте состояния машины состояний (state machine), который генерируется компилятором.
  4. Управление возвращается вызывающему методу. Если это метод верхнего уровня (например, обработчик события), поток освобождается для другой работы.
  5. По завершении асинхронной операции выполнение метода возобновляется, возможно, в другом потоке из пула потоков.

Пример:

public async Task<string> DownloadDataAsync(string url)
{
    // 1. Вызывается асинхронный метод.
    HttpClient client = new HttpClient();
    // 2. При встрече 'await' выполнение приостанавливается,
    //    управление возвращается вызывающему коду.
    string data = await client.GetStringAsync(url);
    // 3. После завершения загрузки выполнение возобновляется здесь.
    return data.ToUpper();
}

Почему это важно: Этот механизм обеспечивает эффективную асинхронность без создания лишних потоков, что критично для масштабируемости приложений (например, веб-серверов).