2009-09-30 4 views
7

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

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

Также идея состоит в том, чтобы сопоставить их очень легко для соответствия nding C++/Python/Java.

ответ

3

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

Мое решение было создать два типа сообщений:

DateTime 
TimeSpan 

Это только потому, что я родом из C# фоне, где эти типы принимаются как само собой разумеющееся.

В ретроспективе TimeSpan и DateTime, возможно, были излишними, но это был «дешевый» способ избежать конверсии с h/m/s в s и наоборот; что сказал, это было бы просто просто реализовать функцию полезности, такие как:

int TimeUtility::ToSeconds(int h, int m, int s) 

BKLYN отметил, что куча памяти используется для вложенных сообщений; в некоторых случаях это явно очень важно - мы всегда должны знать, как используется память. Но в других случаях это может быть менее опасно, когда мы больше беспокоимся об облегчении реализации (это, по-видимому, философия Java/C#).

Существует также небольшой недостаток использования неинтерцируемых типов с protobuf TextFormat::Printer; Вы не можете указать формат, в котором отображается его, поэтому он будет выглядеть примерно так:

my_datetime { 
    seconds: 10 
    minutes: 25 
    hours: 12 
} 

..., который является слишком многословным для некоторых. Тем не менее, было бы труднее прочитать, если бы оно было представлено в считанные секунды.

В заключение, я бы сказал:

  • Если вы беспокоитесь о памяти/разборе эффективности, использование секунд/миллисекунды.
  • Однако, если легкость реализации является целью, используйте вложенные сообщения (DateTime и т. Д.).
2

Извините, не полный ответ, но «я тоже».

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

Объявление вашего сообщения «DateTime» или «FixedPoint» в протограмматике не является решением, потому что вам все равно нужно преобразовать представление вашей платформы в/из сгенерированных объектов вручную, что связано с ошибкой. Кроме того, эти вложенные сообщения сохраняются в виде указателей на объекты, выделенные кучей в C++, что крайне неэффективно, когда базовый тип в основном представляет собой только 64-битное целое число.

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

message Something { 
    required fixed64 time = 1 [cpp_type="boost::posix_time::ptime"]; 
    required int64 price = 2 [cpp_type="fixed_point<int64_t, 4>"]; 
    ... 
}; 

И я должен предоставить все, что клей необходимо преобразовать эти типы в/из fixed64 и int64, чтобы сериализация работала. Может быть, что-то вроде adobe::promote?

3

Вот некоторые идеи, основанные на моем опыте с проводным протоколом, подобным протокольным буферам.

даты и времени (секунды точность)

даты и времени (миллисекунды точность)

Я думаю, что ответ на эти два будет то же самое, вы бы просто обычно иметь дело с меньшим диапазоном чисел в случае точности секунд.

Используйте sint64/sfixed64, чтобы сохранить смещение в секундах/миллисекундах от известной эпохи, такой как полночь GMT 1/1/1970. Это как объекты Date - internally represented in Java. Я уверен, что есть аналоги в Python и C++.

Если вам нужна информация о часовом поясе, пройдите мимо вашей даты/времени с точки зрения UTC и смоделируйте соответствующий часовой пояс как отдельное поле строки. Для этого вы можете использовать идентификаторы из Olson Zoneinfo database, так как это стало стандартным.

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

десятичные с фиксированной точностью

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

В зависимости от того, с какой областью вы работаете, могут быть лучшие решения. Например, если вы моделируете денежное значение, возможно, вам удастся с помощью uint32/64 передать значение в центах, а не дробные долларовые суммы.

Есть также некоторые полезные предложения в this thread.

десятичными с переменной точностью

Не протокол Буфера уже поддерживают это с плавающей точкой/двойными скалярными типами? Возможно, я неправильно понял этот пункт.

В любом случае, если вам нужно обойти эти скалярные типы, вы можете кодировать с использованием IEEE-754 в uint32 или uint64 (float vs double соответственно). Например, Java allows you to extract the IEEE-754 representation и vice versa из объектов Float/Double. Существуют аналогичные механизмы в C++/Python.

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

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

Поскольку в протокольных буферах нет поддержки первого класса, все эти методы требуют небольшого количества " договор между агентами , Возможно, использование соглашения об именах в ваших полях, таких как «_dttm» или «_mask», помогло бы обмениваться данными, когда определенное поле имеет дополнительную семантику кодирования выше и выше по умолчанию для протокольных буферов.

1

Для DateTime с разрешением миллисекунды я использовал int64, который имеет DateTime как YYYYMMDDHHMMSSmmm. Это делает его кратким и читаемым, и, что удивительно, продлится очень долго.

Для десятизначных чисел я использовал byte[], зная, что нет лучшего представления, которое не будет потерять.