提升序列化与谷歌协议缓冲?

时间:2009-06-30 00:02:54

标签: c++ performance serialization protocol-buffers boost-serialization

有这些图书馆经验的人对他们喜欢哪一个有任何评论吗?使用中是否存在任何性能差异或困难?

11 个答案:

答案 0 :(得分:44)

我一直在使用Boost Serialization很长一段时间,只是挖掘协议缓冲区,我认为它们没有完全相同的目的。 BS(没有看到即将发布)将C ++对象保存到流中,而PB是您可以读取/来自的交换格式。

PB的数据模型更简单:你可以获得各种整数和浮点数,字符串,数组,基本结构等等。 BS允许您一步直接保存所有对象。

这意味着使用BS可以在线路上获得更多数据,但是您不必重建所有对象结构,而协议缓冲区更紧凑,但在阅读存档后还有更多工作要做。顾名思义,一个用于协议(语言无关,空间有效的数据传递),另一个用于序列化(保存无脑的对象)。

那么对您来说更重要的是:速度/空间效率还是干净的代码?

答案 1 :(得分:29)

我在这两个系统上玩了一点,没什么大不了的,只是一些简单的hackish东西,但我觉得你应该如何使用这些库有一个真正的区别。

使用boost :: serialization,首先编写自己的结构/类,然后添加归档方法,但是你仍然会留下一些漂亮的“瘦”类,可以用作数据成员,继承,无论如何

使用协议缓冲区,即使是一个简单的结构生成的代码量也相当可观,生成的结构和代码更适用于操作,并且您使用协议缓冲区的功能来传输数据和从您的数据传输数据自己的内部结构。

答案 2 :(得分:26)

还有一些关于boost.serialization的额外问题,我将添加到混音中。警告:除了略读文档之外,我对协议缓冲区没有任何直接经验。

请注意,虽然我认为boost和boost.serialization在它的功能方面非常出色,但我得出的结论是,它带来的默认存档格式对于有线格式来说并不是一个很好的选择。 / em>的

区分您的类的版本(如其他答案中所述,boost.serialization对数据版本控制有一些支持)以及不同版本的序列化库之间的兼容性非常重要EM>

较新版本的boost.serialization may not generate archives that older versions can deserialize(反之亦然:较新版本始终用于反序列化旧版本制作的档案)。这给我们带来了以下问题:

  • 我们的客户和服务器软件创建另一个消耗的序列化对象,因此如果我们以锁步方式升级客户端和服务器,我们只能转移到更新的boost.serialization。 (在您无法完全控制客户的环境中,这是一个相当大的挑战。)
  • Boost捆绑为一个带有共享部分的大型库,序列化代码和boost库的其他部分(例如shared_ptr)可能在同一个文件中使用,我无法升级 any < / em>部分提升因为我无法升级boost.serialization。我不确定尝试将多个版本的boost链接到单个可执行文件中是否可行/安全/合理,或者我们是否有预算/能量将需要保留在较旧版本的boost上的位重构为单独的可执行文件(在我们的例子中是DLL)。
  • 我们坚持使用的旧版本的boost不支持我们使用的最新版本的编译器,所以我们也停留在旧版本的编译器上。

Google似乎实际上publish the protocol buffers wire format,维基百科将它们描述为forwards-compatible, backwards-compatible(尽管我认为维基百科指的是数据版本控制而不是协议缓冲库版本控制)。虽然这些都不是向前兼容性的保证,但对我来说似乎是一个更强有力的指示。

总之,当我无法升级客户端和放大器时,我更喜欢一种众所周知的,已发布的有线格式,如协议缓冲区。锁定服务器。

脚注:由我related answer无耻插件。

答案 3 :(得分:16)

提升序列化

  • 是一个用于将数据写入流的库。
  • 不压缩数据。
  • 不支持自动进行数据版本控制。
  • 支持STL容器。
  • 写入的数据属性取决于所选择的流(例如endian,压缩)。

协议缓冲区

  • 从界面描述中生成代码(默认支持C ++,Python和Java。第三方是C,C#和其他人)。
  • 可选择压缩数据。
  • 自动处理数据版本控制。
  • 处理平台之间的字节序交换。
  • 不支持STL容器。

Boost序列化是一个用于将对象转换为序列化数据流的库。 Protocol Buffers做同样的事情,但也为你做其他工作(比如版本控制和endian交换)。对于“小型简单任务”,Boost序列化更简单。协议缓冲区可能更适合“更大的基础设施”。

编辑:24-11-10:“自动”添加到BS版本。

答案 4 :(得分:14)

我没有使用boost序列化的经验,但我使用了协议缓冲区。我非常喜欢协议缓冲区。记住以下内容(我用没有知识的提升来说明这一点。)

  • 协议缓冲区非常有效,所以我不会想象这是一个严重的问题而不是提升。
  • 协议缓冲区提供了一个适用于其他语言的中间表示(Python和Java ......以及更多工作)。如果您知道自己只使用C ++,那么提升可能会更好,但使用其他语言的选项很不错。
  • 协议缓冲区更像是数据容器......没有面向对象的特性,例如继承。想想你要序列化的结构。
  • 协议缓冲区非常灵活,因为您可以添加“可选”字段。这基本上意味着您可以在不破坏兼容性的情况下更改协议缓冲区的结构。

希望这有帮助。

答案 5 :(得分:11)

boost.serialization只需要C ++编译器,并为你提供一些像

这样的语法糖
serialize_obj >> archive;
// ...
unserialize_obj << archive;

用于保存和加载。如果C ++是你使用的唯一语言,你应该给boost.serialization一个严肃的镜头。

我快速浏览了谷歌协议缓冲区。从我看到的,我说它不能直接与boost.serialization相媲美。您必须将.proto文件的编译器添加到工具链并维护.proto文件本身。 API没有像boost.serialization那样集成到C ++中。

boost.serialization完成了它的设计工作:序列化C ++对象:) OTOH像谷歌协议缓冲区这样的查询API为您提供了更大的灵活性。

因为到目前为止我只使用了boost.serialization,所以我无法评论性能比较。

答案 6 :(得分:7)

关于Boost序列化的更正(猜测为that answer):

它允许支持data versioning

如果您需要压缩 - 请使用压缩流。

可以处理平台之间的字节序交换,因为编码可以是文本,二进制或XML。

答案 7 :(得分:5)

我从来没有使用boost的库实现任何东西,但我发现Google protobuff更加深思熟虑,而且代码更清晰,更易于阅读。我建议你看看你想要使用它的各种语言,并阅读代码和文档,然后下定决心。

我使用protobufs的一个难点是他们在生成的代码GetMessage()中命名了一个非常常用的函数,当然这与Win32 GetMessage宏有冲突。

我仍然强烈推荐protobufs。它们非常有用。

答案 8 :(得分:2)

与工程中的几乎所有内容一样,我的答案是......&#34;它取决于。&#34;

两者都经过严格测试,经过审核的技术。两者都会将您的数据转换为适合发送到某个地方的友好数据。两者都可能足够快,如果你真的在这里或那里计算一个字节,你可能不会对它们感到高兴(让我们面对它,两个创建的数据包都会很小) XML或JSON的一部分。)

对我来说,这真的归结为工作流程,以及你是否需要C ++以外的其他东西。

如果您想先找出邮件内容并从头开始构建系统,请使用Protocol Buffers。您可以以抽象的方式思考消息,然后以您想要的任何语言自动生成代码(第三方插件可用于几乎所有内容)。此外,我发现使用Protocol Buffers简化了协作。我只是发送一个.proto文件,然后另一个团队清楚地知道正在传输什么数据。我也没有对他们施加任何东西。如果他们想使用Java,请继续!

如果我已经在C ++中构建了一个类(并且这种情况经常发生)并且我现在希望通过线路发送数据,那么Boost Serialization显然很有意义(特别是在我已经拥有Boost的情况下)依赖其他地方。)

答案 9 :(得分:0)

您可以使用提升序列化与您的&#34;真实&#34;域对象,并序列化完整的对象层次结构(继承)。 Protobuf不支持继承,因此您必须使用聚合。人们认为Protobuf应该用于DTO(数据传输对象),而不是核心域对象本身。我使用了boost :: serialization和protobuf。应该考虑boost :: serialization的性能,cereal可能是另一种选择。

答案 10 :(得分:0)

我知道现在这是一个较老的问题,但我以为我会把我的2便士扔进去!

通过提升,您有机会在课程中编写一些数据验证;这很好,因为数据定义和有效性检查都在一个地方。

使用GPB,您可以做的最好的事情就是将注释放在.proto文件中,并希望所有希望使用它的人都能阅读它,注意它并自己实现有效性检查。

毋庸置疑,如果您依靠网络流的另一端的其他人以与自己相同的活力来做这件事,这不太可能且不可靠。此外,如果对有效性的约束发生变化,则需要计划,协调和完成多个代码更改。

因此,我认为GPB不适合那些几乎没有机会定期与所有团队成员会面和交谈的开发项目。

== EDIT ==

我的意思是:

message Foo
{
    int32 bearing = 1;
}

现在谁来说明bearing的有效范围是什么?我们可以

message Foo
{
    int32 bearing = 1;  // Valid between 0 and 359
}

但这取决于其他人阅读此内容并为其编写代码。例如,如果您编辑它并且约束变为:

message Foo
{
    int32 bearing = 1;  // Valid between -180 and +180
}

您完全依赖于使用此.proto更新其代码的每个人。这是不可靠和昂贵的。

至少使用Boost序列化,您可以分发单个C ++类,并且可以在其中内置数据有效性检查。如果这些限制发生变化,那么除了确保他们使用与您相同版本的源代码之外,没有其他人需要做任何工作。

<强>替代

还有另一种选择:ASN.1。这很古老,但有一些真正的,非常方便的东西:

Foo ::= SEQUENCE
{
   bearing INTEGER (0..359)
}

注意约束。因此,每当有人使用此.asn文件,生成代码时,他们最终会自动检查bearing介于0和359之间的代码。如果更新.asn文件,

Foo ::= SEQUENCE
{
   bearing INTEGER (-180..180)
}

他们需要做的就是重新编译。无需更改其他代码。

你也可以这样做:

bearingMin INTEGER ::= 0
bearingMax INTEGER ::= 360

Foo ::= SEQUENCE
{
   bearing INTEGER (bearingMin..<bearingMax)
}

请注意<。而且在大多数工具中,bearingMin和bearingMax可以在生成的代码中显示为常量。这非常有用。

约束可以非常详细:

Garr ::= INTEGER (0..10 | 25..32)

请看这PDF中的第13章;你能做什么真是太神奇了;

阵列也可以受到约束:

Bar ::= SEQUENCE (SIZE(1..5)) OF Foo
Sna ::= SEQUENCE (SIZE(5)) OF Foo
Fee ::= SEQUENCE 
{
    boo SEQUENCE (SIZE(1..<6)) OF INTEGER (-180<..<180)
}

ASN.1是老式的,但仍然在积极开发,广泛使用(您的手机使用它很多),并且比大多数其他序列化技术灵活得多。关于我能看到的唯一不足之处是没有适合Python的代码生成器。如果您正在使用C / C ++,C#,Java,ADA,那么您可以通过免费(C / C ++,ADA)和商业(C / C ++,C#,JAVA)工具的混合使用。

我特别喜欢基于二进制和文本的线形图的广泛选择。这使得它在某些项目中非常方便。有线格式列表目前包括:

  • BER(二进制)
  • PER(二进制,对齐和未对齐。这是超级高效的。例如,015之间的INTEGER约束只会占用4 bits
  • OER
  • DER(另一个二进制文件)
  • XML(也是XER)
  • JSON(全新,工具支持仍在开发中)

加上其他人。

注意最后两个?是的,您可以在ASN.1中定义数据结构,生成代码,以及使用XML和JSON发出/使用消息。对于20世纪80年代开始的技术来说还不错。

版本控制与GPB不同。您可以允许扩展名:

Foo ::= SEQUENCE
{
   bearing INTEGER (-180..180),
   ...
}

这意味着以后我可以添加到Foo,拥有此版本的旧系统仍可以使用(但只能访问bearing字段)。

我非常高评价ASN.1。处理可能是一种痛苦(工具可能需要花钱,生成的代码不一定很漂亮等)。但限制是一个真正奇妙的功能,一次又一次地让我心痛。当编码器/解码器报告他们已经生成了duff数据时,开发人员会抱怨很多。

其他链接:

<强>观察

分享数据:

  • 代码优先方法(例如Boost序列化)限制您使用原始语言(例如C ++),或强迫您使用其他语言执行大量额外工作
  • 架构首先更好,但是
    • 其中很多在共享合同中留下了很大的空白(即没有约束)。 GPB在这方面很烦人,因为它非常好。
    • 有些人有约束(例如XSD,JSON),但遭受补丁工具支持。
    • 例如,微软的xsd.exe主动忽略了xsd文件中的约束(MS的借口真的很虚弱)。 XSD很好(从约束的角度来看),但是如果你不能相信另一个人使用一个很好的XSD工具为他/她强制执行它们,那么XSD的价值就会降低
    • JSON验证器没问题,但它们没有帮助您首先形成JSON,也没有自动调用。无法保证发送给您JSON消息的人通过验证器运行它。你必须记住自己验证它。
    • ASN.1工具似乎都实现了约束检查。

所以对我来说,ASN.1做到了。它是最不可能导致其他人犯错误的那个,因为它是具有正确功能的工具,并且所有工具似乎都在努力完全实现这些功能,并且它是语言中立的足以满足大多数目的。

老实说,如果GPB增加了一个成为赢家的约束机制。 XSD很接近,但工具几乎普遍是垃圾。如果有其他语言的代码生成器,JSON模式会很好。

如果GPB添加了约束(注意:这不会改变任何有线格式),那就是我几乎为所有目的推荐的人。虽然ASN.1的uPER对无线电链路非常有用。