Обновить

Комментарии 9

Очень хороший материал, спасибо

Спасибо большое! Такие отзывы мотивируют писать дальше)

я бы еще в подводные камни добавил работу с исключениями. Есть определенные нюансы при работе с AsyncEnumerable

Не подумал про это! Спасибо большое!

А какие там нюансы, вкратце?

Если вкратце, основные нюансы такие:

  1. Асинхронный итератор не выполняется не выполняется до начала перечисления. Поэтому исключение вылетит не в момент вызова метода, а только на await foreach. Это такой небольшой и понятный нюанс но просто нужно про него помнить.

  2. Еще yield нельзя обернуть в try/catch. Разрешён только try/finally. То есть если к примеру в середине сессии случится разрыв соедниения с базой, то поймать и обработать ошибку прямо внутри итератора вокруг выдачи элементов не получится. Ловить приходится вокруг await foreach.

  3. Нужно не забывать помечать CancellationToken параметром [EnumeratorCancellation] иначе в методы после компиляции пропихнется не раельный токен а CancellationToken.None. В целом, забыть сложно, так как компилятор отметит этот момент в коде. Но это тоже нюанс. В примерах как раз все отмечено как надо

  4. Это не совсем про примеры из статьи. Но есть нюанс, что finally в асинхронном итераторе отработает даже если цикл перечисления прервать. Проще всего на вот таком коде это показать:

async IAsyncEnumerable<int> ReadAsync()
{
    Console.WriteLine("открыли ресурс");
    try
    {
        for (int i = 0; i < 100; i++)
        {
            await Task.Delay(10);
            yield return i;
        }
    }
    finally
    {
        // сюда попадём даже если потребитель прервётся на середине
        Console.WriteLine("закрыли ресурс");
    }
}

await foreach (var x in ReadAsync())
{
    Console.WriteLine(x);
    if (x == 3) break;   // прерываем не доходя до конца цикла из 100 итераций и думаем что код из строчки 15 не выполнится
}

// Но оказывается что код выполнится, хотя вроде цикл мы прервали посередине

Вот такой вывод получится:
открыли ресурс
0
1
2
3
закрыли ресурс   <- finally всё равно отработал

// Еще интересно что фактически выполнение вот этого метода 

Console.WriteLine("закрыли ресурс");

// будет вызвано в контексте вот этого метода:
await foreach (var x in ReadAsync())
{
    Console.WriteLine(x);
    if (x == 3) break;   // прерываем не доходя до конца цикла из 100 итераций и думаем что код из строчки 15 не выполнится
}

Спасибо.

Если вам нужен стриминг данных, то самое подходящее это веб-сокеты, нет?

Да, это действительно хорошая штука, но вся прелесть в веб-сокетах, что это двухсторонняя связь! То есть вы можете гонять пакеты туда, сюда и вообще построить кучу взаимодействий на этой штуке.

Но для некоторых сценариев это абсолютный оверкилл. К примеру если вы стримите логи, то нет никакого смысла в двухсторонней связи. А чтобы настроить ws придется повозиться. Поднять SignalR чтобы у вас связь корректно работала на нескольких копиях приложения к примеру.

В общем да, веб-сокеты это топ, просто геморный и вот для описанных сценариев легче без него)

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации