Comments 17
В 90е никто в критических по производительности местах токены никуда не перекладывал, все старались делать за один проход конечным автоматом, символ за символом, без malloc
А расскажите пожалуйста, в чём преимущество перед стандартным парсером из System.Text.Json? Есть ли бенчмарки? Кажется, что даже десятки мегабайт, прочитанные один раз (речь ведь про настройки) не должны стать проблемой
А расскажите пожалуйста, в чём преимущество перед стандартным парсером из System.Text.Json?
Преимущество в том, что такой парсер работает в любой версии Unity и как и .NET. Этот парсер часть генерируемого кода тулы для чтения игровых конфигов. Мне неизвестно, где незвестно где этот код будет запущен. Оно плавно деградирует (через #if) до самых плохих условий исполнения и работает везде. В то время как System.Text.Json хочет свои зависимости и правильный рантайм со Span и ReadOnlySequence.
Есть ли бенчмарки?
Только что сделал 10mb JSON на .NET Framework 4.7.1 (Core могут быть чуть другие результаты):
| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen0 | Gen1 | Gen2 | Allocated | Alloc Ratio |
|------------------------------- |---------:|---------:|---------:|------:|--------:|----------:|---------:|---------:|----------:|------------:|
| JsonFormatter | 74.45 ms | 1.163 ms | 1.384 ms | 1.03 | 0.03 | 3714.2857 | 142.8571 | - | 23.82 MB | 1.05 |
| SystemTextJsonFormatter | 72.40 ms | 0.607 ms | 0.538 ms | 1.00 | 0.00 | 3714.2857 | - | - | 22.64 MB | 1.00 |
| JsonFormatterWithStringPooling | 65.76 ms | 0.743 ms | 0.695 ms | 0.91 | 0.01 | 2500.0000 | 750.0000 | 250.0000 | 14.98 MB | 0.66 |
Кажется, что даже десятки мегабайт, прочитанные один раз (речь ведь про настройки) не должны стать проблемой
Вот это только токенизация 10Mb JSON т.е. "Read() + reader.GetString()/GetInt()", а еще сколько занимает создание объектов и складывание в них. Представьте теперь вместо моего современного PC процессора мобильный процессор который троттлится от жары.
А зачем вы тогда используете формат json, а не готовую структуру байт которую можно замаппить в самом приложении, и тут не будет никакого лишнего парсинга.
Ну используйте свой json и храните его в гите, а при билде в приложение подсовывать готовое упакованное представление. И зачем тогда нужны все эти оптимизации?
У каждого разработчика игр свой ответ на этот вопрос. За очень редким исключением большинство выбирают текстовые форматы для хранения игровых конфигов.
Мои ответы:
а) один источник правды - сам JSON/YAML/INI/CSV файл
б) возможность по-быстрому подправить и перезапустить игру без экспортов в бинарный формат
в) возможность моддерам без доп инструментов что-то добавить/убрать/затюнить
Вспомнился simdjson отсюда https://habr.com/ru/companies/quadcode/articles/660229/
Возникает вопрос, может быть стоит конвертировать данные в более удобный для машины бинарный формат?
Да, есть еще вариант хранить в формате MessagePack, и даже есть парсер который в 2.7х быстрее чем JSON. Но у бинарных форматов есть огромный минус, они плохо диффятся и мержатся в системах контроля версий. Даже без мержей, просто посмотреть что поменялось в бинарном файле невозможно.
А если взять Твместо JSON s-expressions?
Ребята в яндексе как раз подбное делали:
https://youtu.be/H6Lb5L5A_2c?t=802
simdjson уже упомянули, бинарные форматы упомянули, остаётся ещё yyjson упомянуть. Ну и конечно в статье про улучшение производительности очень нехватает результатов замеров до и после (и в процессе), понять получилось быстро или медленно (относительно лучших существующих решений) невозможно. О файлах какого размера речь хотя бы идёт? И о каком времени обработки? И что мешает взять существующие библиотеки в проект, где важна производительность?
Ну и конечно в статье про улучшение производительности очень нехватает результатов замеров до и после (и в процессе), понять получилось быстро или медленно (относительно лучших существующих решений) невозможно. О файлах какого размера речь хотя бы идёт? И о каком времени обработки? И что мешает взять существующие библиотеки в проект, где важна производительность?
В комментарии https://habr.com/ru/articles/828502/comments/#comment_27035122 есть ответы на все эти вопросы и бенчмарк.
Если речь о utf8 то есть смысл сравнить с https://github.com/neuecc/Utf8Json там много оптимизаций именно под utf8, к сожалению проект в архиве, но сами подходы там интересные
Это смешно без тестов скорости. И что значит парсинг? - в структуру? В интерфейс? В переменные? Сколько строк в секунду этот парсер обрабатывает?
Как только в unity завезли парсинг напрямую из Span, я переписал сериализаторы практически без выделений.
Основа это два класса, где внутри данные на основе чанков. Первый это структуры нодов, второй это куски байт данных.
При парстнге строится дерево в глубину. Ссылки на данные по индексу во втором классе.
Если данные это строки, то да, создается string. А если нет, то парсится, без лишних преобразований.
Первый это структуры нодов, второй это куски байт данных.
Второй ReadOnlySequence<T> который набор сегментов с ссылкой на Next. А можете показать код первого для изучения, если это не секрет.
Как я улучшил производительность JSON-парсера в два раза