11

我想找出存储协议缓冲区支持的列表中未包含的一些常见数据类型的最佳方法是什么。

  • 日期时间(秒精度)
  • 日期时间(毫秒精度)
  • 具有固定精度的小数
  • 精度可变的小数
  • 很多布尔值(如果你有很多它们,由于它们的标签,看起来你每个人都会有 1-2 个字节的开销。

这个想法也很容易将它们映射到相应的 C++/Python/Java 数据类型。

4

4 回答 4

3

以下是基于我对类似于 Protocol Buffers 的有线协议的经验的一些想法。

日期时间(秒精度)

日期时间(毫秒精度)

我认为这两个的答案是相同的,在秒精度的情况下,您通常只会处理较小范围的数字。

使用 sint64/sfixed64 以秒/毫秒为单位存储从某个众所周知的纪元(如 1970 年 1 月 1 日午夜 GMT)的偏移量。这就是 Date 对象在 Java 中的内部表示方式。我确信 Python 和 C++ 中有类似物。

如果您需要时区信息,请根据 UTC 传递您的日期/时间,并将相关时区建模为单独的字符串字段。为此,您可以使用Olson Zoneinfo 数据库中的标识符,因为这已成为某种标准。

这样,您就有了日期/时间的规范表示,但您也可以本地化到任何相关的时区。

具有固定精度的小数

我的第一个想法是使用类似于从 Python 的 decimal 包中构造 Decimal 对象的字符串。我想这相对于某些数字表示可能效率低下。

根据您使用的域,可能会有更好的解决方案。例如,如果您正在建模货币价值,也许您可​​以使用 uint32/64 来传达以美分为单位的价值,而不是小数美元金额。

这个线程中也有一些有用的建议。

精度可变的小数

协议缓冲区不是已经支持浮点/双标量类型了吗?也许我误解了这个要点。

无论如何,如果您需要绕过这些标量类型,您可以使用 IEEE-754 编码为 uint32 或 uint64(分别为浮点型和双精度型)。例如,Java允许您从 Float/Double 对象中提取 IEEE-754 表示,反之亦然。C++/Python 中有类似的机制。

很多布尔值(如果你有很多它们,由于它们的标签,看起来你每个人都会有 1-2 个字节的开销。

如果您担心线路上浪费的字节,您可以使用位掩码技术将许多布尔值压缩为单个 uint32 或 uint64。

因为在 Protocol Buffers 中没有一流的支持,所有这些技术都需要代理之间的一些君子契约。当给定字段具有超出协议缓冲区默认行为的附加编码语义时,也许在您的字段上使用命名约定(如“_dttm”或“_mask”)将有助于沟通。

于 2009-11-18T21:11:16.803 回答
3

protobuf 的设计原理最有可能使数据类型支持尽可能“原生”,以便将来轻松采用新语言。我想他们可以提供内置消息类型,但你在哪里画线?

我的解决方案是创建两种消息类型:

DateTime
TimeSpan

这只是因为我来自 C# 背景,这些类型被认为是理所当然的。

回想起来,TimeSpanDateTime可能是矫枉过正,但这是避免从 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等)。
于 2009-12-24T10:44:18.547 回答
2

对不起,不是一个完整的答案,而是一个“我也是”。

我认为这是一个很好的问题,我很想自己回答。无法本地描述基本类型,如日期时间和(对于金融应用程序)定点小数,或将它们映射到语言指定或用户定义的类型,这对我来说是一个真正的杀手。它或多或少地阻止了我使用图书馆,否则我认为这很棒。

在 proto 语法中声明您自己的“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之类的东西?

于 2009-10-14T22:26:44.710 回答
1

对于具有毫秒分辨率的日期时间,我使用了一个int64日期时间为YYYYMMDDHHMMSSmmm. 这使得它既简洁又易读,而且令人惊讶的是,它会持续很长时间。

对于小数,我使用byte[],知道没有更好的表示不会有损。

于 2016-03-22T13:16:25.130 回答