Комментарии 2
Но в промышленных системах с тысячами событий это становится проблемой — потребовалась бы дополнительная буферизация данных, чтобы не захлебнуться в их потоке.
Хотелось бы увидеть конкретные цифры, какой-нибудь бенчмарк, чтобы понять, что именно и с чем мы сравниваем. Почему события захлёбываются, а IAsyncEnumerable - нет, если в конечном счёте и то и другое утыкается в UI, доступ к которому сериализован?
[...] появилась возможность использовать IAsyncEnumerable, позволяющие реализовать код профессионального уровня с линейной сигнатурой и преимуществами такими как:
Полное соответствие концепции чистой архитектуры
Масштабируемость
Полной контроль над потоками данных
Тестируемость
Отменяемость
Читаемость
Слабая связанность
Что такое "полное соответствие концепции чистой архитектуры"? Чем отличается от неполного?
Что такое "полный контроль над потоками данных"? Чем отличается от неполного? Почему у событий нет полного контроля? Почему нет остальных преимуществ?
Спасибо за вопросы — они по делу.
Начну с бенчмарков: их нет, и это честно. Чтобы сделать показательный тест, нужен целый проект, а на это уйдёт время. Если вам интересно — можете сами прогнать, я буду только рад увидеть цифры. Но суть не в скорости, а в управляемости: события толкают данные сами, а IAsyncEnumerable позволяет тебе решать, когда их брать. Это не «быстрее», это «удобнее» для сложных сценариев.
По поводу UI — вы правы, в конечном счёте всё упирается в UI. Но разница в том, кто задаёт темп: события могут захлебнуться, если данные летят быстрее, чем ты успеваешь их обрабатывать — и тогда приходится буферизировать вручную, что ведёт к росту памяти и нагрузке на GC. IAsyncEnumerable даёт контроль: хочешь — обрабатывай быстро, хочешь — поставь паузу.
«Полное соответствие чистой архитектуре» — громко сказано, согласен. В примере из статьи я использую прямое создание экземпляра FindDevicesService, чтобы не усложнять код и сфокусироваться на IAsyncEnumerable. В реальных проектах я использую DI и интерфейсы, но в статье это опущено, чтобы не отвлекать. Суть подхода — не в интерфейсах, а в управляемом потоке данных, отменяемости и линейном коде без Dispatcher.Invoke.
«Контроль над потоком» — это про возможность остановить, притормозить, отменить или перераспределить данные. События так не умеют: ты подписался — и данные летят сами, независимо от твоей готовности.
Статья не претендует на истину в последней инстанции. Это мой практический опыт, как уйти от Dispatcher.Invoke и событийного ада. Если есть конкретные сценарии, где этот подход не работает — буду рад обсудить. А с бенчмарками вы правы — было бы круто их добавить, но это уже за рамками формата.

Практическое применение линейной реализации асинхронных операций на примере WPF приложения