Войти
ФлеймФорумПроЭкты

Умный бинарный формат (2 стр)

Advanced: Тема повышенной сложности или важная.

Страницы: 1 2
#15
15:20, 24 ноя. 2018

gammaker
> Если поменялись параметры, но эти различия можно выразить через старые
> параметры, то это реализуется через вычисляемые свойства.
Таких изменений будет примерно 0%. Если разработчики заранее знали какие свойства можно бы добавить, они с тем же успехом могли их добавить сразу. Ну т.е. в случае Image - если ты заранее знаешь что изображения бывают неквадратными, то кто мешает вместо вычисляемых полей сразу передавать два измерения. 4 байта экономии на картинку? Тогда ты вряд ли добавишь эти поля в будущем.
А расширять формат ты будешь когда выяснится что с картинкой надо передавать DPI, или скажем отсылать ее в CMYK, в общем делать то что не предусмотрел в первой версии.


#16
16:47, 24 ноя. 2018

kipar
> Таких изменений будет примерно 0%.
Думаю, что всё же побольше. Например, я использую вычисляемые свойства, чтобы задать значение в некотором диапазоне. Допустим, у нас некоторый параметр изменяется в интервале 3456 - 3678. Любое число из этого интервала можно представить в виде int16, а можно сделать поле типа uint8 и свойство, которое прибавляет 3456 к этому полю. И если мы храним миллион таких структур, то мы уже экономим мегабайт. Свойства позволяют прозрачно для программы переходить от первого варианта ко второму и наоборот. Физическая структура данных меняется, а логически она та же самая.

>Если разработчики заранее знали какие
> свойства можно бы добавить, они с тем же успехом могли их добавить сразу.
Зачем тратить байты на то, что может не понадобиться?

kipar
> 4 байта экономии на картинку?
Это я конечно дурацкий пример привёл, первое что пришло в голову. Но можно найти другие применения, когда экономия пары байт в структуре даст огромную выгоду, например в ситуации, которую я описал в начале этого поста.

kipar
> А расширять формат ты будешь когда выяснится что с картинкой надо передавать DPI
Просто добавить поле DPI и это все изменения. А при чтении старых файлов использовать значение по умолчанию. С этим бы даже protobuf бы справился.

kipar
> или скажем отсылать ее в CMYK
Это просто изменит физический тип поля Data, не изменяя логического. При сериализации / десериализации оно будет корректно переконвертировано в нужный формат.

#17
22:36, 24 ноя. 2018

Дич какая-то дикая. Либо быстро и платформозависимо. Либо медленно, строчками ASCII и float/double/int.

#18
23:17, 24 ноя. 2018

lookid
> Дич какая-то дикая. Либо быстро и платформозависимо. Либо медленно, строчками
> ASCII и float/double/int.
Можно и средне через бинарное представление форматов типа json/xml, etc.
Ускоряется паркинг, уменьшается объем памяти, но конечно блокнотом не поредактировать

#19
23:38, 24 ноя. 2018

Кстaти, а я ведь намедни предлагал:
http://gamedev.ru/flame/forum/?id=238115

#20
2:50, 25 ноя. 2018

А чем этот формат лучше, чем ASN.1 ?

#21
(Правка: 18:55) 18:54, 25 ноя. 2018

lookid
> Дич какая-то дикая. Либо быстро и платформозависимо. Либо медленно, строчками
> ASCII и float/double/int.
С чего ты так решил? Байты - они везде байты, на разных архитектурах может отличаться только порядок Little Endian и Big Endian. IEEE 754 тоже в наше время поддерживается везде. Если файл содержит информацию о том, в каком порядке байт хранятся данные, то парсер может проверить это. В случае совпадения он может замапить напрямую данные на структуры и массивы в программе без десериализации. В случае несовпадения - сконвертировать при первом чтении, записать сконвертированный файл куда-нибудь в кеш, а дальше доставать из кеша файл нативного формата.

KILLJOY
> А чем этот формат лучше, чем ASN.1 ?
ASN.1 решает только проблему платформозависимости бинарных данных. При этом он не описывает физическую структуру файла, а только логическую. И логическую структуру он описывает гораздо хуже, чем мой формат - только на низком уровне - число, строка, массив и ограничения на их интервалы.
Например мой формат позволяет контролировать каждый бит каждого поля. Например можно сделать даже компактно упакованный массив 19-битных интов. Можно описать структуру BMP, PNG или любого другого из существующих форматов или даже самого себя - по крайней мере, я над этим работаю и уже близок к этой цели. А в ASN.1, protobuf и прочих подобных есть только некоторое подмножество фич для создания новых кастомных форматов без особого контроля над тем, как там всё кодируется. Описать себя они только не в состоянии.

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

#22
1:24, 28 ноя. 2018

Давай сразу JPG

#23
10:45, 28 ноя. 2018

KILLJOY
> Давай сразу JPG
У меня уже PNG в процессе, а с JPG я мало знаком. Может как-нибудь потом.

#24
14:34, 28 ноя. 2018

  Смахивает на очередное рукоблудие.
  Всё описанное достигается с помощью protobuf. Хотя сами проблемы описаны как-то мутно. Проблема Big/Little Endian сегодня возникает примерно никогда. То, что формат хранения данных на диске должен определять способ хранения этих данных в памяти процесса это лютейший бред. Одни и те же данные можно распихать по оперативке как угодно не меняя при этом формата хранения или наоборот записать по другому. Те же базы данных и ORM в пример. Если уж даже в protobuf остались какие-то проблемы, то в любой другой альтернативе их будет ещё больше. И зачем, в таком случае кому-то может понадобиться поделка неизвестного анонима даже если предположить, что там не будет багов и ей не нужна будет поддержка (что, естественно, невыполнимо)?

#25
14:59, 28 ноя. 2018

Пример решения подобной задачи "по месту" и "на коленке" (боян): https://gcup.ru/forum/62-45089-2#698967

#26
(Правка: 17:16) 16:51, 28 ноя. 2018

Zefick
> То, что формат хранения данных на диске должен определять способ хранения этих
> данных в памяти процесса это лютейший бред.
Это ещё почему? Скорость же. Прочитал одним куском без парсинга и можно работать. Или можно даже в память замапить, не читая с диска всё.
Protobuf тормозной и так не может. А у Flatbuffers свои ограничения.
Особенно в игровых движках актуально, поэтому все делают свои форматы, когда можно сразу считать и запихнуть в видеокарту. И моя разработка в этом очень поможет, потому что позволяет ясным языком указать, какой формат мы хотим, вместо того, чтобы вручную писать код записи и чтения формата.

Zefick
> Одни и те же данные можно распихать по оперативке как угодно не меняя при этом
> формата хранения или наоборот записать по другому.
И то же самое я предлагаю для файлов. Одни и те же логически данные можно писать в файл по-разному. Потом программа говорит, как она хочет разложить их в оперативке. Если способ раскладки внутри файла и желаемый способ в оперативке совпадают, то файл считывается в оперативку быстро как есть. Если нет, то всё автоматически конвертируется - не надо писать никакого ручного кода.

Zefick
> И зачем, в таком случае кому-то может понадобиться поделка неизвестного анонима
Если так говорить, то можно просто запретить всем кроме гуглов что-то там разрабатывать.
Тому, что я делаю, аналогов в мире нет. Область применения этого в десятки раз шире всех форматов вместе взятых, потому что решает все проблемы: сложности описания, создания и поддержки (версионности) бинарных форматов, преобразований между форматами, компактности, эффективности. И даже, в перспективе, человекочитаемости - пусть файлы и бинарные, но будет единая утилита, которая сможет открыть абсолютно любой бинарный файл, созданный по моей технологии, показать его в человекочитаемом формате и даже отобразить картинки и воспроизвести звуки, которые в нём закодированы. И она даже сможет открыть обычный "неумный" файл, если рядом будет лежать описание его формата.

Zefick
> Проблема Big/Little Endian сегодня возникает примерно никогда.
Есть форматы и протоколы, где используется Big-Endian кодирование и его поддержка в моём формате пригодится для их поддержки.

Первое, что я предлагаю - это формальный язык описания структуры файла, который сможет понять компьютер и автоматически сгенерировать готовый к использованию парсер и экспортер. Вместо того, чтобы писать громоздкие спецификации форматов, где человеческим текстом и таблицами написано, как там байты разложены и как его парсить, я предлагаю писать на языке, который будет понятен не только человеку, но и компьютеру. Написал такую спецификацию своего формата и не надо ничего реализовывать - сразу же можно его применять в любом языке программирования, куда доберётся моя библиотека.
Скоро будет пример описания структуры формата PNG на моём языке. Я много искал, но не нашёл ни одного языка, который бы мог описать какой-нибудь существующий формат, например PNG или хотя бы даже TGA. Ближайшие аналоги - Protobuf и ASN.1 точно не могут, потому что у них для этого слишком примитивный язык описания схемы.

#27
(Правка: 19:57) 19:53, 28 ноя. 2018

gammaker
> Protobuf тормозной и так не может.
  Тем не менее ты предлагаешь то же самое и непонятно откуда там возьмётся скорость. Ты думаешь авторы protobuf об этом не думали?
  И там, где нужна скорость, никто и не будет использовать какие-то непонятные либы, которые обещают сказочные ништяки непонятно с чего. Обычно либо мирятся с накладными расходами либо мирятся.

> А у Flatbuffers свои ограничения.
  Скорее всего эти ограничения опять вытекают из её возможностей (в частности кроссплатформенность) и являются трейд-оффами.

> Тому, что я делаю, аналогов в мире нет.
  Под конкретную задачу всегда найдётся свой аналог. Не всем нужна поддержка кучи языков (которую, я думаю, ты не осилишь) и они давно нашли нужное решение для своего. В Java, например, есть библиотека Kryo, которая решает многие проблемы встроенной сериализации, а также добавляет ей в скорости и уменьшает размер выходных файлов. То, что она самая популярная говорит о том, что больше никому не удалось сделать что-то лучше. Причём так как в Java есть рефлексия, то все эти пляски с бубном вокруг написания каких-то там файлов на непонятном языке автоматически становятся не нужны. На хрена кому-то может понадобится кроссплатформенное решение, не учитывающее особенности платформы явы и игнорирующее её преимущества, мне решительно непонятно.
  А кому нужна поддержка нескольких языков те, скорее всего, пишут микросервисы, где скорость сериализации вообще почти ни на что не влияет. И тут как раз вкатывается protobuf. А если ты пытаешься угодить сразу всем, то не получится угодить никому.

#28
21:32, 28 ноя. 2018

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

Zefick
> Скорее всего эти ограничения опять вытекают из её возможностей (в частности
> кроссплатформенность) и являются трейд-оффами.
А мой язык не содержит никаких трейд-оффов вообще. Пользователю предоставляется неограниченная свобода продумать свой формат до всех деталей, описывая его на моём языке, и самому решить, какие у него будут трейд-оффы. Если нужна компактность, а скорость не важна, он может экономить каждый бит и применять сжатие, если наоборот, то можно расположить данные, да ещё и с выравниванием так, чтобы это можно было сразу мапить в оперативку и работать. Или может даже создать оба варианта и прозрачно для программы переключаться между ними.

Zefick
> Под конкретную задачу всегда найдётся свой аналог.
Давай я тебе опишу задачу, с которой столкнулся на работе и ты подберёшь решение, которое я мог бы использовать для её решения. Лично я не нашёл ничего подходящего и пришлось пилить свой кастомный формат. Если бы моя технология была уже готова, я бы мог сделать это за 5 минут, а не за пару дней, при этом оно было бы гораздо более поддерживаемым и гибким в долгосрочной перспективе.
Итак, есть устройства, которые регистрируют значения некоторых параметров, которых около тысячи. Параметры приходят от внешнего устройства, на каждый параметр отводится от 1 до 19 бит и они либо дискретные (чаще всего false / true), либо это числа с фиксированной запятой в некотором интервале. Нужно все эти параметры записывать в файл и при наличии Интернет-соединения отправлять на сервер. Необходимо при этом минимизировать трафик, занимаемое на сервере пространство, а также нагрузку на сервер при приёме и раздаче этих данных клиентом. Поэтому, очевидно, пришлось параметры хранить плотно, выделяя им в файле ровно столько бит, сколько нужно для хранения этого параметра. Было решено также сжимать наборы значений для каждого параметра индивидуально, чтобы сервер мог выдирать из файла и сразу выдавать сжатые блоки клиентам, которые хотят построить график какого-то конкретного параметра - сразу все 1000 его не интересуют. Таким образом, клиент только принимает файл и кладёт его себе туда, где он сможет его найти по запросу от клиента.
Устройство-регистратор и сервер написаны на Go. Клиент будет написан на TypeScript и выполняться в браузере. Именно на него будет возложена работа по анализу данных. Клиент запрашивает нужные параметры за некоторый промежуток времени у сервера, получает набор сжатых блоков, их разжимает, распаковывает побитово запакованные параметры и рисует их график, либо выполняет какие-то другие задачи по анализу данных.
Технологию, привязанную к какому-то одному языку использовать нельзя, потому что используется два разных языка. А что бы мне дал Protobuf? Он не умеет битовую запаковку и не умеет сжатие. Пришлось бы это в любом случае делать руками и передавать туда просто тупой массив байт. А это как раз самая трудоёмкая часть, которую придётся ещё и на двух языках реализовывать.
Ещё нужно учитывать, что устройство-регистратор слабое - одно ARM-ядро с частотой 800 MHz и памятью 512 МБ, наверняка Protobuf дал бы ещё и оверхед огромный, и при этом не принёс бы практически никакой пользы.
На моём языке формат, который пришлось вручную реализовывать, описывается в 10 строчек, и можно использовать.

Zefick
> Причём так как в Java есть рефлексия, то все эти пляски с бубном вокруг
> написания каких-то там файлов на непонятном языке автоматически становятся не нужны.
Так с рефлексией писать их и не обязательно. Но на языке можно описать зависимости, свойства и другие логические элементы структуры, которые через рефлексию не получить. И язык этот вполне себе понятный, потому что ясно описывает структуру того, что мы хотим получить.

Zefick
> На хрена кому-то может понадобится кроссплатформенное решение, не учитывающее
> особенности платформы явы и игнорирующее её преимущества, мне решительно
> непонятно.
С чего ты решил, что не учитывающее? По мере развития можно учитывать все преимущества всех языков и платформ, ведь ограничений никаких не накладывается.

#29
21:59, 28 ноя. 2018

Zefick
> есть библиотека Kryo

TaggedFieldSerializer
...
Additionally, a varint is written before each field for the tag value.

тоесть похоже они даже не хранят описание используемый типов в сериализованом виде или хотя бы hash от него.
CompatibleFieldSerializer
Additionally, the first time the class is encountered in the serialized bytes, a simple schema is written containing the field name strings

о, круто, хранят описание типов, прям как у меня, хотя не совсем, у меня описание всё вначале файла/потока находится. правда не понятно почему упомянуты только имена полей, но ничего не сказано про типы.

хотя readUnknownTagData как бы намекает, что наверно перед каждым объектом/полем храниться его тип или что-то типа указателя на тип, что как бы раздувает бинарное представление. ещё есть надежда что "a simple schema is written" подразумевает не только имена полей, а ещё и типы полей.

readUnknownTagData
When true, the class for each field value is written before the value. When an unknown field is encountered, an attempt to read the data is made. This is used to skip the data and, if references are enabled, any other values in the object graph referencing that data can still be deserialized. If reading the data fails (eg the class is unknown or has been removed) then an exception is thrown or, if chunkedEncoding is true, the data is skipped.

непонятно как может появиться unknown field если у них перед каждым полем храниться тип поля и где-то валяется "a simple schema" для каждого типа.
Страницы: 1 2
ФлеймФорумПроЭкты