Сериализация в byte[]
От: f95.2  
Дата: 06.05.20 19:09
Оценка:
Добрый вечер.

Я хочу сериализовать объекты определенного типа в byte[] (или список из byte[]), чтобы послать их по сети.
Причем, перед отправкой самого объекта надо отправить длину его байтового представления.

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

И что-то я не могу найти хороший способ сериализовтаь объект.
Варианты, которые я нашел:
1. ByteArrayOutputStream. Держит в себе массив,который при необходимости реаллоцирует.
Проблемы:
а) при реаллокации содержимое старого массива копируется в новый. Кажется, лучше подошла бы структура, которая хранила бы список из нескольких масивов.
б) Чтобы получить byte[], надо вызвать метод toByteArray(), который создает новый массив и копирует туда содержимое ByteArrayOutputStream.
А мне массив по факту нужен только для чтения, поэтому в этом копировании смысла нет.

2. ArrayList<Byte>
Проблемы:
а) Ходят слухи, что работа с обертками значительно медленнее работы с примитивами.
б) напрямую его по сети не послать, нужно всё равно формировать byte[], да еще и заполнять его поэлементно, а не через arraycopy.


Что в подобных случаях используют джависты?
Или может я зря загоняюсь, и на этот оверхед вообще нет смысла обращать внимания?
Но ведь на джаве вроде как пишут и хайлоад в том числе, должен же быть функционал, который позволит делать работу без лишнего оверхеда.
Re: Сериализация в byte[]
От: kov_serg Россия  
Дата: 06.05.20 19:33
Оценка: +1
Здравствуйте, f95.2, Вы писали:

F2>Добрый вечер.

Начните копать отсюда: https://github.com/EsotericSoftware/kryo
Re[2]: Сериализация в byte[]
От: f95.2  
Дата: 06.05.20 19:45
Оценка:
Здравствуйте, kov_serg, Вы писали:
_>Начните копать отсюда: https://github.com/EsotericSoftware/kryo

Спасибо, я посмотрю.
Но вообще, в вопросе я имел в виду стандартные средства.
Понятно, что всегда можно взять стороннюю библиотеку или даже самому написать нужный функционал.
Re: Сериализация в byte[]
От: vsb Казахстан  
Дата: 06.05.20 20:20
Оценка: +2
Ты С++-ник что ли? Ну скопирует массив байтов и что? У тебя сериализуются гигабайты? Сомневаюсь. В общем не заморачивайся и используй ByteArrayOutputStream, а на копирования байтов не смотри, затыка у тебя там с вероятностью в 99% не будет. Не стоит пытаться оптимизировать на мелочах, причем еще до того, как проблема возникла. Что-что, а память нынешние компьютеры копируют очень быстро.

Хайлоад это не то, что оптимизировано до последнего байта. Это то, что масштабируется на кучу серверов.

Если ты хочешь считать байты, бери Rust или C.
Отредактировано 06.05.2020 20:22 vsb . Предыдущая версия . Еще …
Отредактировано 06.05.2020 20:20 vsb . Предыдущая версия .
Re: Сериализация в byte[]
От: · Великобритания  
Дата: 06.05.20 20:48
Оценка: +1
Здравствуйте, f95.2, Вы писали:

f> 1. ByteArrayOutputStream. Держит в себе массив,который при необходимости реаллоцирует.

Преаллоцируй заранее. _Если только_ профайлер покажет проблему с производительностью.

f> Проблемы:

f> а) при реаллокации содержимое старого массива копируется в новый. Кажется, лучше подошла бы структура, которая хранила бы список из нескольких масивов.
Чем лучше?

f> б) Чтобы получить byte[], надо вызвать метод toByteArray(), который создает новый массив и копирует туда содержимое ByteArrayOutputStream.

f> А мне массив по факту нужен только для чтения, поэтому в этом копировании смысла нет.
Можно использовать метод writeTo.

f> 2. ArrayList<Byte>

Нет, конечно.
Ещё java.nio.Buffer есть

f> Что в подобных случаях используют джависты?

Обычно берут готовую либу для сериализации. avro/protobuf/sbe/json/xml, сотни их. Переизобретать свой формат — моветон.

f> Или может я зря загоняюсь, и на этот оверхед вообще нет смысла обращать внимания?

Обычно это называется premature optimisation.

f> Но ведь на джаве вроде как пишут и хайлоад в том числе, должен же быть функционал, который позволит делать работу без лишнего оверхеда.

Самый быстрый алгоритм обычно такой — под сообщение предвыделяют макс буфер (сообщения невлезающие шлют чанками). Отступают 4 байта от начала буфера, пишут содержимое считая размер, пишут размер в первые 4 байта.
avalon/2.0.6
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[3]: Сериализация в byte[]
От: GarryIV  
Дата: 06.05.20 20:52
Оценка:
Здравствуйте, f95.2, Вы писали:

_>>Начните копать отсюда: https://github.com/EsotericSoftware/kryo


F2>Спасибо, я посмотрю.

F2>Но вообще, в вопросе я имел в виду стандартные средства.
F2>Понятно, что всегда можно взять стороннюю библиотеку или даже самому написать нужный функционал.

Ну если тебе хочется именно стандарного:
https://docs.oracle.com/en/java/javase/12/docs/api/java.base/java/io/Serializable.html
https://docs.oracle.com/en/java/javase/12/docs/api/java.base/java/io/Externalizable.html
WBR, Igor Evgrafov
Re[2]: Сериализация в byte[]
От: f95.2  
Дата: 06.05.20 22:29
Оценка:
Здравствуйте, vsb, Вы писали:

vsb>Ты С++-ник что ли?

Угу. Профдеформация сказывается

vsb>Ну скопирует массив байтов и что? У тебя сериализуются гигабайты? Сомневаюсь.

Вообще, у меня пет-проект, который я пишу для изучения джавы.
Я, естественно, не ожидаю, что программа джаве будет работать также быстро и эффективно, как и нативный код,
но еще не разобрался, насколько сильно тут принято экономить ресурсы, особенно память.
Судя по всему, о ней вообще не думают...

vsb> причем еще до того, как проблема возникла

Так проблема возникла. Просто заключается она не в том, чтобы код написать и ускорить, а в том,
чтобы разобраться, какие есть типовые варианты решения и какие у них плюсы и минусы.
Re[3]: Сериализация в byte[]
От: vsb Казахстан  
Дата: 06.05.20 22:40
Оценка:
Здравствуйте, f95.2, Вы писали:

F2>Судя по всему, о ней вообще не думают...


Думают об алгоритмах. Думают о конкретной реализации, если очевидно, что данных очень много. Т.е. если ты реально будешь сериализовать объект в гигабайты, там да, можно и массив массивов сварганить (стандартного класса нет, в других библиотеках не видел такого). Хотя там уже лучше думать о том, как это всё передать не накапливая данные в памяти.

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

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

F2>Так проблема возникла. Просто заключается она не в том, чтобы код написать и ускорить, а в том,

F2>чтобы разобраться, какие есть типовые варианты решения и какие у них плюсы и минусы.

Типовой вариант решения это ByteArrayOutputStream. А то, что он там копирует, это уже не твои проблемы. Реально он воде каждый раз в 2 раза буфер увеличивает, т.е. копирований будет логарифм от максимального размера, т.е. немного. Такого, что на каждый записанный байт будет заново копироваться не будет, квадратичного роста времени выполнения здесь нет.

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

Это я к подходу Java подвожу (: Не руками всё делаем, а слепливаем решение из готовых библиотек.

При этом, конечно, понимать, что происходит в твоём коде, надо.

Вроде были какие-то странные люди, которые пишут упоротый код, вплоть до того, чтобы там вообще не было ни одной аллокации после инициализации. Типа кода, который должен отвечать за гарантированное и очень малое время, например робот, торгующий на бирже. Там да, подобный подход идёт лесом и надо "считать байты". Но зачем они используют Java и потом борются с ней, я не знаю.
Отредактировано 06.05.2020 22:43 vsb . Предыдущая версия . Еще …
Отредактировано 06.05.2020 22:41 vsb . Предыдущая версия .
Re[2]: Сериализация в byte[]
От: f95.2  
Дата: 06.05.20 22:42
Оценка:
Здравствуйте, ·, Вы писали:

·>Преаллоцируй заранее. _Если только_ профайлер покажет проблему с производительностью.

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

·>Чем лучше?

Так на переаллокациях и копированиях экономим

·>Можно использовать метод writeTo.

Спасибо. Что-то я как-то пропустил его.

·>Переизобретать свой формат — моветон.

Ну формат не мой, я только пишу парсер/сериализатор.
И только как модельную программу с целью изучения языка.

·>Обычно это называется premature optimisation.

Ну это в продакшене, а в учебном проекте она не premature даже когда еще ни строчки кода не написано

·>Самый быстрый алгоритм обычно такой — под сообщение предвыделяют макс буфер (сообщения невлезающие шлют чанками). Отступают 4 байта от начала буфера, пишут содержимое считая размер, пишут размер в первые 4 байта.

Ясно, спс. Буду пробовать реализовать.
Re[3]: Сериализация в byte[]
От: · Великобритания  
Дата: 06.05.20 22:47
Оценка:
Здравствуйте, f95.2, Вы писали:

f> но еще не разобрался, насколько сильно тут принято экономить ресурсы, особенно память.

Когда надо экономят, когда не надо — не экономят. Второй вариант на практике встречается гораздо чаще.
Хуже того, у java очень мощный JIT и рассуждать о производительности кода довольно сложно. Иногда может случиться так, что все эти лишние выделения внезапно исчезнут. Единственный вменяемый вариант — берём JMH Benchmark в зубы и сравниваем разные решения по нужным критериям.

f> Судя по всему, о ней вообще не думают...

Это ты просто не о том думаешь... Вроде как бы рассуждаешь о микрооптимизациях и тут же спрашиваешь как сериализовать int в десятичном представлении... Java тут вообще побоку
avalon/2.0.6
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[4]: Сериализация в byte[]
От: f95.2  
Дата: 06.05.20 22:50
Оценка:
·>Это ты просто не о том думаешь... Вроде как бы рассуждаешь о микрооптимизациях и тут же спрашиваешь как сериализовать int в десятичном представлении...
А шо поделать, если протокол такой?
Re[3]: Сериализация в byte[]
От: · Великобритания  
Дата: 06.05.20 22:57
Оценка:
Здравствуйте, f95.2, Вы писали:

f> ·>Преаллоцируй заранее. _Если только_ профайлер покажет проблему с производительностью.

f> Ну я хотел через какой-то поток, потому что в поток джавовские типы писаться умеют,
f> а в байтовый массив приходится руками (ну или я не знаю каноничного способа).
Байтовый массив произвольного размера скорее всего ошибка в дизайне.

f> ·>Чем лучше?

f> Так на переаллокациях и копированиях экономим
Зато теряем на нелокальности и косвенности.

f> ·>Переизобретать свой формат — моветон.

f> Ну формат не мой, я только пишу парсер/сериализатор.
В смысле какой-то пропиетарный? Тогда да, дело дрянь, пиши сам, прогоняй профайлером возможные подходы. Непонятно тогда почему ты надеешься увидеть какое-то стандартное решение.
avalon/2.0.6
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[4]: Сериализация в byte[]
От: f95.2  
Дата: 06.05.20 23:11
Оценка:
·>В смысле какой-то пропиетарный?
В смысле FIX.

.>Непонятно тогда почему ты надеешься увидеть какое-то стандартное решение.

????
Я надеюсь увидеть стандартное решение стандартной проблемы.
Это проект, на котором я язык изучаю. И готовое решение я не беру именно из-за того,
что хочу разобраться как тут программы писать.
Re: Сериализация в byte[]
От: scf  
Дата: 07.05.20 03:56
Оценка: +2
Здравствуйте, f95.2, Вы писали:

F2>Что в подобных случаях используют джависты?

F2>Или может я зря загоняюсь, и на этот оверхед вообще нет смысла обращать внимания?
F2>Но ведь на джаве вроде как пишут и хайлоад в том числе, должен же быть функционал, который позволит делать работу без лишнего оверхеда.

В JVM очень дешевая аллокация, намного дешевле, чем у большинства плюсовых аллокаторов. Вкратце, каждый поток имеет собственный пул памяти и для аллокации достаточно сделать инкремент указателя, без всяких списков свободных блоков.
Поэтому копирование памяти при удвоении массива — это быстро. Если немного посчитать, такая реализация в среднем все равно обеспечивает добавление одного элемента за константное время.

Теперь о сериализации, вот варианты сериализации данных, по увеличению эффективности:
— Java serialization. Встроено в jvm, но медленно работает и неэффективный формат
— JSON/Jackson. Для 99% это работает достаточно быстро, если данные отправляются по HTTP/gzip — это еще и достаточно компактно
— protobuf/flatbuffers. Используют кодогенерацию для эффективной сериализации

Более тонкие оптимизации, такие как преаллокация и повторное буфера использование буфера, потоковые сериализаторы, работа с DirectByteBuffer или напрямую с нативной памятью, нужно использовать аккуратно и обязательно тестировать быстродействие, т.к. даже "топорные" с точки зрения разработчика С++ реализации могут работать быстро.

На современных машинах даже JSON-ом можно легко забить гигабитный канал, поэтому заморачиваются только ради низких latency или при совсем возмутительной нехватке серверов.
Re: Сериализация в byte[]
От: varenikAA  
Дата: 07.05.20 05:49
Оценка:
Здравствуйте, f95.2, Вы писали:

F2>Добрый вечер.


F2>Я хочу сериализовать объекты определенного типа в byte[] (или список из byte[]), чтобы послать их по сети.

Извиняюсь конечно, но куда послать по сети? Помню раньше для создания распределенных приложений использовался Java RMI.
Другое дело если вы отправляете в чужое приложение, тогда принимающая сторона определяет и формат и протокол.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[5]: Сериализация в byte[]
От: GarryIV  
Дата: 07.05.20 06:11
Оценка:
Здравствуйте, f95.2, Вы писали:

F2>Я надеюсь увидеть стандартное решение стандартной проблемы.

F2>Это проект, на котором я язык изучаю. И готовое решение я не беру именно из-за того,
F2>что хочу разобраться как тут программы писать.

Стандартное решение в Java это использовать стандартные сетевые протоколы для которых есть 100500 готовых решений на всех уровнях (не только и не столько [де]сериализация).

Впрочем я как то раз писал сервер для странного сетевого протокола, придуманного сумрачным гением в компании. Использовал netty, в нем есть средства для этого.

Сколько у тебя транзакций в секунду планируется? Какое допустимое время обработки запроса?
WBR, Igor Evgrafov
Отредактировано 07.05.2020 6:34 GarryIV . Предыдущая версия .
Re[5]: Сериализация в byte[]
От: · Великобритания  
Дата: 07.05.20 08:03
Оценка: 9 (1)
Здравствуйте, f95.2, Вы писали:

f> ·>В смысле какой-то пропиетарный?

f> В смысле FIX.
Ну так сразу бы и сказал. Теперь рассказывай чем quickfixj не устраивает?

f> .>Непонятно тогда почему ты надеешься увидеть какое-то стандартное решение.

f> ????
f> Я надеюсь увидеть стандартное решение стандартной проблемы.
Программы очень по-разному пишутся в зависимости от требований.
Скажем, quickfixj простой, но в общем-то так себе по скорости, сорит. Есть коммерческие библиотеки для low latency, zero-gc стиль использовать — сложно, но очень быстро. Можно и самому написать, но для этого надо обширный опыт иметь.

f> Это проект, на котором я язык изучаю. И готовое решение я не беру именно из-за того,

f> что хочу разобраться как тут программы писать.
Тогда опен-сорсные либы для тебя — самое то — берёшь, начинаешь использовать, смотришь внутрь, разбираясь как устроено, дополняешь, исправляешь, пишешь похожее.
avalon/2.0.6
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.