proto3 - поля oneof vs с идентификатором

Я пишу класс proto3 для объекта, который в настоящее время имеет около двух вариаций и вырастет до 6 или 7. Только один из них будет использоваться в сообщении. Эти варианты не имеют общих полей. Они будут закодированы как вложенное сообщение в родительском сообщении. Эти сообщения будут написаны один раз и прочитаны десятки тысяч раз.

Мне было интересно, какой способ, память и время синтаксического анализа был бы наиболее эффективным, чтобы достичь этого, чтобы при добавлении большего количества вариантов производительность не терялась.

Рассмотрим следующие варианты.

message B1 {
    repeated string value = 1;
    bool hasMeta = 2;
}

message B2 {
    repeated int32 value = 1;
    map<string, string> foo = 2;
}

Первый вариант: определите поле oneof, которое относится к конкретному подтипу.

message P1 {
    oneof parents {
        B1 boo = 1;
        B2 baz = 2;
        // add more variations here in future..
    }
    // other non-related fields...
}

Второй вариант: определите целое число, которое действует как идентификатор доступного варианта. Во время выполнения это целое число может использоваться для определения того, какой вариант был установлен (другой способ - обнулить варианты и использовать первое ненулевое значение).

message P1 {
    int32 type = 1;
    B1 boo = 2;
    B2 baz = 3;
    // other non-related fields...
}

Меня особенно интересуют размер провода и его характеристики.

Во втором варианте, учитывая, что будет установлен только один из вариантов (применяется на уровне приложения), будет ли размер провода больше, чем в первом? Зарезервирована ли память и для нулевых полей?


person Termin4t0r    schedule 20.03.2020    source источник


Ответы (1)


Метод oneof немного лучше по сравнению с сообщением, в котором вы определяете переменную type в отношении вычислительной мощности и размера провода. Protobuf всегда сериализует номер тега перед вложенным сообщением. Таким образом, для сообщения oneof не требуется сериализовать переменную типа type. Делаем его размер провода немного меньше по сравнению со вторым определением сообщения.

Что касается распределения памяти, это сильно зависит от языка программирования, который вы используете, и от того, как они реализовали oneof и вложенные сообщения. Если я не ошибаюсь, реализация C ++ по умолчанию динамически выделяет память для дополнительных сообщений. Я подозреваю, что здесь нет никакой разницы между любым из ваших предложений. Однако если посмотреть на NanoPB, то там oneof реализованы как объединения, выделяющие только память для более крупного сообщения. В то время как для вашего второго варианта будет выделена память как для B1, так и для B2.

person Bart    schedule 24.03.2020
comment
Это Java-приложение, и я использую библиотеку Google protobuf-java. - person Termin4t0r; 25.03.2020
comment
К сожалению, я ничего не знаю о реализации java. Может быть, вы могли бы посмотреть в коде или спросить конкретно, как распределяются вложенные сообщения по сравнению с oneof. - person Bart; 26.03.2020
comment
OP Я тоже использую Java, удалось ли вам изучить использование памяти? - person Walton; 13.01.2021