TGStat
TGStat
Введите текст для поиска
Расширенный поиск каналов
  • flag Russian
    Язык сайта
    flag Russian flag English flag Uzbek
  • Вход на сайт
  • Каталог
    Каталог каналов и чатов Региональные подборки Тематические подборки Платные каналы Поиск каналов
    Добавить канал/чат
  • Рейтинги
    Рейтинг каналов Рейтинг чатов Рейтинг публикаций
    Рейтинги брендов и персон
  • Аналитика
  • Поиск по публикациям
  • Мониторинг Telegram
  • Продвижение
    Реклама через Яндекс Бизнес Реклама в каналах через TGStat Agency Реклама на сайте TGStat.ru
.NET Разработчик

8 Sep, 08:01

Открыть в Telegram Поделиться Пожаловаться

День 2778. #ЗаметкиНаПолях
Потоковая Передача JSON в .NET. Начало
Допустим, у вас есть конечная точка, которая возвращает список: все заказы за последний квартал или поток показаний датчиков. Код выглядит нормально:
app.MapGet("/orders/export",
async (OrderService service) =>
{
List orders = await service.GetAllAsync();
return Results.Ok(orders);
});
GetAllAsync извлекает все строки в List. Затем Results.Ok передаёт весь список сериализатору, который формирует JSON-массив в памяти. Т.е. вы храните две копии данных одновременно — объекты и их сериализованную форму, — а клиент ждёт, пока не будет сериализована последняя строка, прежде чем что-либо получить.

Для пары сотен строк это не заметно. При паре десятков тысяч происходит скачок потребления памяти, начинает работать сборщик мусора, и время до получения первого байта растёт, как и нагрузка на процесс при увеличении количества одновременных запросов. Решение в том, чтобы прекратить буферизацию. Сериализуем элемент, отдаём, переходим к следующему.

System.Text.Json может передавать IAsyncEnumerable потоком начиная с .NET 6. Платформа выдаёт JSON-массив потоком, а не буферизирует его:
// возвращает IAsyncEnumerable
app.MapGet("/orders/export", (OrderService service) =>
service.GetAllAsyncStream());

…

public async IAsyncEnumerable
GetAllAsyncStream(
[EnumeratorCancellation] CancellationToken ct = default)
{
await foreach (var order in _repo.ReadAllAsync(ct))
yield return order;
}
Это решает проблему использования памяти. Сервер хранит один заказ за раз, а не весь список. Вывод – JSON-массив:
[{"Id":1,"Total":42.0},{"Id":2,"Total":19.5}, …]

Это вполне приемлемо для браузера, вызывающего функцию fetch и использующего await res.json(). Но есть недостаток для больших объёмов данных: массив представляет собой один JSON-документ. Потребитель, желающий обрабатывать элементы по мере их поступления, должен разбирать массив постепенно, и, если соединение обрывается на полпути, остается усечённый, некорректный JSON-документ — завершающий символ ] не доходит. Добавить к нему данные тоже невозможно. Для потоковой обработки, записи в лог или экспорта данных JSON-массив имеет неправильный формат.

Окончание следует…

Источник:
https://thecodeman.net/posts/streaming-json-in-dotnet-with-json-lines

1.6k 2 23 6
Каталог
Каталог каналов и чатов Подборки каналов Поиск каналов Добавить канал/чат
Рейтинги
Рейтинг каналов Telegram Рейтинг чатов Telegram Рейтинг публикаций Рейтинги брендов и персон
API
API статистики API поиска публикаций API Callback
Наши каналы
@TGStat @TGStat_Chat @telepulse @TGStatAPI
Почитать
Академия TGStat Исследование Telegram 2019 Исследование Telegram 2021 Исследование Telegram 2023
Контакты
Справочный центр Поддержка Почта Вакансии
Всякая всячина
Пользовательское соглашение Политика конфиденциальности Публичная оферта
Наши боты
@TGStat_Bot @SearcheeBot @TGAlertsBot @tg_analytics_bot @TGStatChatBot