【问题标题】:Why does protobuf include datatype in the serialized data?为什么 protobuf 在序列化数据中包含数据类型?
【发布时间】:2020-08-11 18:35:30
【问题描述】:

Protobuf 在序列化数据中包含数据类型(Thrift 也这样做)。但是,读取数据的应用程序应该能够从模式中获取此信息。

我能想到的唯一可以从这种设计中受益的场景是用户完全丢失了架构信息。比如说,他们的机器完全坏了,源代码和模式没有存储在其他任何地方。他们正在尝试从需要反序列化数据自包含的硬盘驱动器中恢复数据。但我怀疑这种设计是否涵盖了这种极为罕见的情况。

另外,在序列化中排除数据类型绝对可以在一定程度上节省空间,而不会影响运行时性能。有什么想法吗?

【问题讨论】:

    标签: protocol-buffers


    【解决方案1】:

    Protobuf 在序列化数据中包含数据类型

    通常不会,它不会。唯一这样做的时候是您使用 Any 类型(当它需要知道您存储了哪个 message 时),或者您使用的库对类型元数据有一些非标准支持。它通常不会存储有关类型的任何内容 - 仅存储字段编号和电线类型。我怀疑您对正在查看的数据有误解。


    如果您是指电线类型;它需要能够跳过(或逐字存储,用于往返)它知道的字段(不 在它生成的架构中)。线路类型没有足够的信息来理解字段内容 - 如果没有架构,它会非常模棱两可 - 例如“长度前缀”可以表示至少 4 种不同的数据类型。最终,它是 3 位,并与字段号一起 打包;大多数时候(嗯,七分之四,包括字段 1-15)它甚至不需要额外的字节。

    从这个角度来看,在 xml 中,查找当前值结尾的规则是:

    • 如果是属性,则查找结束符"
    • 如果它是一个元素,则寻找一个结束 </theElementName>(考虑到任何嵌套)

    这里的电线类型定义了同样的东西:

    • 对于 varint:最多读取(包括)未设置高位的下一个字节(预计最多 10 个)
    • 对于 64 位:读取 8 个字节
    • 对于 32 位:读取 4 个字节
    • 对于定界的长度:读取一个 varint,然后读取那么多字节
    • 对于起始组:读取到匹配的结束组(考虑到任何嵌套)

    所以这就是告诉你什么时候该停止,如果你还不能知道那是因为你没想到那个领域。

    【讨论】:

    • 感谢您的详细解释,Marc。我正在阅读“设计数据密集型应用程序”一书,其中讨论了“节俭和协议”部分中的 protobuf 编码,它在图 4-4 中给出了一个示例(抱歉,我在 stackoverflow 上的排名不允许我插入屏幕截图)。虽然它没有提到这个“电线类型”的细节,但在我看来,它所谈论的类型是 this,这对我来说很有意义 - 所有类型都是 3 位,它们与字段标签共享相同的字节(我绝对不相信谷歌会设计出效率不高的东西:))。
    • 也就是说,我仍然对所有 3 个不同字符串“Martin”、“daydreaming”和“hacking”具有相同编码线类型“010”的示例感到困惑。此外,它在编码类型上方有一些文本,并暗示它们代表字符串。这对你有意义吗?
    • @CodingFanSteve 这里的 010 是电线类型 2,“以长度为前缀”,这只是表示长度在字段标题之后以 varint 形式表示。所有 UTF-8 string 数据都使用线路类型 2。但其他 3 种数据类型也使用。
    猜你喜欢
    • 1970-01-01
    • 2020-05-28
    • 2017-11-11
    • 1970-01-01
    • 2018-10-18
    • 2013-07-15
    • 1970-01-01
    • 1970-01-01
    • 2011-07-29
    相关资源
    最近更新 更多