TGViewer
.NET Разработчик .NET Разработчик @netdeveloperdiary · 6.75K subscribers
Post #1259 1.62K
День 1029. #ЗаметкиНаПолях #AsyncTips
Создание асинхронных потоков

Задача
Нужно вернуть несколько значений, при этом каждое значение может потребовать некоторой асинхронной работы.

Решение
Возвращение нескольких значений из метода может осуществляться командой yield return, а асинхронные методы используют async и await. Асинхронные потоки (асинхронные перечисления) объединяют эти два подхода. Используйте возвращаемый тип IAsyncEnumerable<T>. В следующем примере асинхронно перебираются результаты API, использующего параметры для страничной организации результатов:
async IAsyncEnumerable<string> GetAsync(HttpClient client)
{
int off = 0;
const int lim = 10;
while (true)
{
// Получаем текущую страницу результатов
var result = await client.GetStringAsync(
$"{apiURL}/values?offset={off}&limit={lim}"
);
var values = result.Split('\n');

// Выдаём результаты с этой страницы
foreach (var value in values)
yield return value;

// Если последняя страница, выходим
if (values.Length != lim)
break;
// Переходим к следующей странице
off += lim;
}
}

Когда метод GetAsync начинает работу, он асинхронный запрашивает первую страницу данных, после чего производит первый элемент. Второй элемент выдаётся немедленно, потому что он содержится на той же странице данных. И т.д. 10 элементов. При запросе 11-го элемента цикл foreach завершится, выполнение цикла while продолжится. На следующей итерации цикла while выполнится асинхронный запрос второй страницы данных, после чего будет выдан 11-й элемент. И т.д…

В течение многих лет использовать async и await с yield return было невозможно, но асинхронные потоки ввели эту возможность. В примере выше стоит обратить внимание, что асинхронная работа нужна не для всех результатов. Здесь только приблизительно одному из каждых 10 элементов потребуется асинхронная работа. Если размер страницы равен 20, то асинхронная работа потребуется только одному из 20 элементов.
Это обычное поведение с асинхронными потоками. Для многих потоков большинство операций асинхронного перебора на самом деле синхронно; асинхронные потоки только позволяют асинхронно получить любой следующий элемент. Асинхронные потоки проектировались с учетом как асинхронного, так и синхронного кода; вот почему они построены на основе ValueTask<T>.

Когда вы реализуете асинхронные потоки, подумайте о поддержке отмены. Некоторые сценарии не требуют реальной отмены: потребляющий код всегда может отказаться от получения следующего элемента. Это абсолютно нормальный подход при отсутствии внешнего источника для отмены. Если вы хотите, чтобы асинхронный поток можно было отменить даже в процессе получения следующего элемента, то следует обеспечить поддержку отмены с использованием CancellationToken.

Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 3.
  • 👍 1
More from @netdeveloperdiary
  1. Oct 3, 2026Post #3360
  2. Oct 3, 2026День 2803. #Оффтоп Чем Заняться, Пока Работают Агенты? У VS Code Есть Ответ Сейчас большую…
  3. Oct 2, 2026День 2802. #Карьера #Юмор Секреты Программирования, Известные Только Легендам Ещё один пос…
  4. Oct 1, 2026Post #3357
  5. Sep 30, 2026Post #3356
  6. Sep 29, 2026Фото 3 (с) Анатолий Кулаков
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →