Как работает сериализация MicroStream (de)? - PullRequest
0 голосов
/ 06 ноября 2019

Мне было интересно, как сериализация MicroStream работает в деталях. Поскольку он описывается как «Супербыстрый», он должен опираться на генерацию кода, верно? Или он основан на отражениях?
Как бы он работал по сравнению с сериализацией Protobuf-Serialization, которая основывается на генерации кода, которая непосредственно считывает поля java и записывает их в байтовый буфер, и наоборот.
Использование отражений значительно уменьшило бы производительность при сериализации объектов в огромном масштабе, не так ли?

Я ищу быстрый способ передачи и сохранения объектов для многопользовательской игры, и каждая миллисекунда считается. :)

Заранее спасибо!

PS: Так как у меня недостаточно репутации, я не могу создать тег "microstream". https://microstream.one/

1 Ответ

1 голос
/ 13 ноября 2019

Я ведущий разработчик MicroStream. (Это не псевдоним учетной записи. Я действительно только что создал ее. Я читаю в StackOverflow около 10 лет, но у меня никогда не было причин для создания учетной записи. До сих пор.)

При каждой инициализации MicroStream анализирует текущие версии времени выполнения всех необходимых классов сущностей и типов значений и извлекает из них оптимизированные метаданные. То же самое делается при встрече с классом во время выполнения, который до сих пор был неизвестен. Анализ выполняется для каждого отражения, но поскольку он выполняется только один раз для каждого обработанного класса, затраты на производительность отражения незначительны. Фактическое хранение и загрузка или сериализация и десериализация выполняются с помощью оптимизированного кода платформы на основе созданных метаданных.

Если изменяется макет класса, анализ типа создает отображение из макета поля, в котором хранятся экземпляры класса. в том из текущего класса. Автоматически, если это возможно (однозначные изменения или с помощью некоторой настраиваемой эвристики), в противном случае с помощью предоставленного пользователем отображения. Производительность остается неизменной, поскольку JVM не волнует, копирует ли оно (упрощенно говоря) загруженное значение № 3 в положение № 3 или в положение № 5. Это все в метаданных.

Используются ByteBuffers, точнее, прямые ByteBuffers, но только в качестве якоря для памяти вне кучи для работы через прямые "небезопасные" операции низкого уровня. Если вы не знакомы с «небезопасными» операциями, короткое и простое понятие: «Это так же быстро и быстро, как код C ++». Вы можете делать все, что хотите, очень быстро и близко к памяти, но вы также несете ответственность за все. Для получения более подробной информации, Google "sun.misc.Unsafe".

Код не генерируется. Никакого взлома байтового кода, молчаливой замены экземпляров прокси-серверами или подобными обезьянами. На техническом уровне это просто библиотека Java (включая использование «небезопасных»), но с большим количеством правильно разработанной логики.

В качестве примечания: отражение не такое медленное, как принято считать,Уже нет. Это было, но это было оптимизировано в значительной степени в некоторых прошлых версиях Java (s?). Это только медленно, если каждая операция должна выполнять весь анализ классов, поиск полей и т. Д. Заново (что, похоже, делает очень много фреймворков, потому что они просто плохо написаны). Если поля собираются (устанавливаются доступными и т. Д.) Один раз, а затем кэшируются, отражение на самом деле удивительно быстро.

Что касается сравнения с Protobuf-Serialization:

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

Большинство подходов к сериализации отказываются от ссылочной согласованности, но сохраняют только «данные» (т. Е. Если два объектассылаясь на третье, десериализация создаст ДВУХ экземпляров этого третьего объекта. Например: A-> C <-B == serialization ==> A-> C1 B-> C2. Это в основном разрушает / разрушает / разрушает графы объектов и делаетСериализация циклических графов невозможна, поскольку она создает и бесконечно каскадную репликацию. См., например, сериализация JSON. Забавные вещи. Даже проект Брайана Гетца для Java «Сериализация 2.0» включает это ограничение (см. «Ограничения» в http://cr.openjdk.java.net/~briangoetz/amber/serialization.html) (и еще один, который нарушает разделение интересов).

MicroStream не имеет этого ограничения. Он правильно обрабатывает произвольные графы объектов, не разрушая их ссылок. Сохранение целостности ссылочной целостности далеко не является«пытается сделать слишком много», как он пишет. Это "делает это правильно". Нужно просто знать, как это сделать правильно. И это даже довольно тривиально, если все сделано правильно. Таким образом, в зависимости от того, сколько ограничений имеет Protobuf-Serialization («пакт с дьяволом»), она может быть едва ли или вообще не сравнима с MicroStream в целом.

Конечно, вы всегда можете создать несколько тестов для сравнения производительности для ваших конкретных требований и посмотреть, какая технология вам больше подходит. Просто убедитесь, что вы знаете об ограничениях, налагаемых на вас определенной технологией (нарушенная ссылочная согласованность, запрещенные типы, требуемые аннотации, требуемый конструктор / получатель / установщик по умолчанию и т. Д.). MicroStream не имеет ни одного *.

(*) в пределах разумного: Сериализация / хранение внутренних компонентов системы (например, Thread) или не-сущностей (таких как экземпляры лямбда-выражения или прокси), хотя и технически возможно, намеренно исключены.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...