Каковы наиболее заметные различия между буферами протокола Google и ASN.1 (с PER-кодированием)? Для моего проекта наиболее важной проблемой является размер сериализованных данных. Кто-нибудь сделал какие-либо сравнения размеров данных между этими двумя?
Как сопоставить буферы протокола Google с ASN.1
Ответ 1
Я долгое время занимался какой-либо работой ASN.1, но размер, скорее всего, будет зависеть от деталей ваших типов и фактических данных.
Я бы настоятельно рекомендовал вам прототипировать оба и поместить некоторые реальные данные для сравнения.
Если ваш буфер протокола будет содержать повторяющиеся примитивные типы, вы должны посмотреть на последний источник в Subversion for Protocol Buffers - они могут быть представлены в "упакованном" формате, который теперь намного эффективнее. (Мой порт С# только что догнал эту функцию, некоторое время на прошлой неделе.)
Ответ 2
Если вы используете ASN.1 с Unaligned PER и определяете свои типы данных с использованием соответствующих ограничений (например, указывая нижние/верхние границы для целых чисел, верхние границы для длины списков и т.д.), ваши кодировки будут очень компактный. Не будет битов впустую для таких вещей, как выравнивание или заполнение между полями, и каждое поле будет закодировано в минимальном количестве бит, необходимых для хранения разрешенного диапазона значений. Например, поле типа INTEGER (1..8) будет закодировано в 3 бита (1 = '000', 2 = '001',..., 8 = '111'); и ВЫБОР с четырьмя альтернативами будет занимать 2 бита (с указанием выбранной альтернативы) плюс бит, занятый выбранной альтернативой. ASN.1 имеет много других интересных функций, которые были успешно использованы во многих опубликованных стандартах. Примером может служить маркер расширения ( "..." ), который при применении к SEQUENCE, CHOICE, ENUMERATED и другим типам обеспечивает обратную и прямую совместимость между конечными точками, реализующими разные версии спецификации.
Ответ 3
Когда размер упакованного/закодированного сообщения важен, вы также должны отметить тот факт, что protobuf не может упаковать поля repeated
, которые не относятся к primitive numeric type
, прочитайте это для получения дополнительной информации.
Это проблема, например. если у вас есть сообщения этого типа: (комментарий определяет действительный диапазон значений)
message P{
required sint32 x = 1; // -0x1ffff to 0x20000
required sint32 y = 2; // -0x1ffff to 0x20000
required sint32 z = 3; // -0x319c to 0x3200
}
message Array{
repeated P ps = 1;
optional uint32 somemoredata = 2;
}
Если длина массива равна, например, 32, то вы получите размер упакованного сообщения приблизительно 250-450 байт с protobuf, в зависимости от того, какие значения фактически содержит массив. Это может даже увеличиться до более чем 1000 байтов, если вы используете полный 32-битный диапазон или, если вы используете int32
вместо sint32
и имеете отрицательные значения.
Необработанный блок данных (предполагая, что z может быть определен как значение int16
), будет потреблять только 320 байт, поэтому сообщение ASN.1 всегда меньше, чем 320 байт, так как максимальные значения на самом деле не 32 бит, а 19 бит (x, y) и 15 бит (z).
Размер сообщения protobuf можно оптимизировать с помощью этого определения сообщения:
message Ps{
repeated sint32 xs = 1 [packed=true];
repeated sint32 ys = 2 [packed=true];
repeated sint32 zs = 3 [packed=true];
}
message Array{
required Ps ps = 1;
optional uint32 somemoredata = 2;
}
что приводит к размерам сообщений приблизительно от 100 байт (все значения равны нулю), 300 байт (значения в диапазоне max) и 500 байт (все значения имеют высокие 32-битные значения).