В чем разница между yield return и async/await в C#?

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

Ответ

yield return и async/await — это два разных механизма языка C# для реализации ленивого выполнения и асинхронности соответственно. Их нельзя смешивать.

yield return (Итераторы)

  • Назначение: Поэлементная ленивая генерация последовательностей (IEnumerable<T>) без загрузки всей коллекции в память.
  • Контекст: Работает строго в синхронном коде.
  • Управление потоком: Не освобождает текущий поток. Выполнение метода-итератора приостанавливается на yield return и возобновляется при следующем запросе элемента.

Пример:

IEnumerable<int> GenerateFibonacci(int count) {
    int a = 0, b = 1;
    for (int i = 0; i < count; i++) {
        yield return a;
        int temp = a;
        a = b;
        b = temp + b;
    }
}
// Использование: foreach (var num in GenerateFibonacci(10)) { ... }
// Память: в один момент времени в памяти только одно число.

async/await (Асинхронное программирование)

  • Назначение: Выполнение неблокирующих операций, обычно связанных с вводом-выводом (I/O): работа с сетью, файлами, БД.
  • Контекст: Работает в асинхронном контексте.
  • Управление потоком: Ключевое слово await освобождает текущий поток (например, поток пула) на время выполнения асинхронной операции, позволяя ему выполнять другую работу.

Пример:

async Task<string> DownloadContentAsync(string url) {
    using var httpClient = new HttpClient();
    // Поток освобождается на время загрузки
    string content = await httpClient.GetStringAsync(url);
    return content.ToUpper();
}

Сравнительная таблица

Характеристика yield return async / await
Возвращаемый тип IEnumerable<T>, IEnumerator<T> Task, Task<T>, ValueTask
Цель Ленивые последовательности Асинхронные операции (I/O, CPU-bound)
Освобождение потока Нет Да (на время await)
Ключевые слова yield return, yield break async, await
Можно ли совмещать? Нет. yield return нельзя использовать в async-методе. Нет. await нельзя использовать в методе с yield return.

Важно: Для асинхронного ленивого перечисления в .NET существует IAsyncEnumerable<T> с await foreach.