Ответ
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.