web-dev-qa-db-ja.com

シリアライゼーションとグーグルプロトコルバッファーを強化しますか?

これらのライブラリを使用した経験のある人は、どちらを好んだかについてコメントがありますか?パフォーマンスの違いや使用上の問題はありましたか?

64
0xC0DEFACE

私は両方のシステムで少し遊んだことがありますが、深刻なことは何もありません。単純なハックなものだけですが、ライブラリの使用方法には実際の違いがあると感じました。

Boost :: serializationを使用すると、最初に独自の構造体/クラスを記述してから、アーカイブメソッドを追加しますが、データメンバーとして使用したり、継承したりできる、かなり「スリムな」クラスが残ります。

プロトコルバッファーを使用すると、単純な構造でも生成されるコードの量はかなり多くなります。生成される構造体とコードは操作のためのものであり、プロトコルバッファーの機能を使用して、独自の内部構造との間でデータを転送します。 。

29

私はBoost Serializationを長い間使用しており、プロトコルバッファーを掘り下げていましたが、それらにはまったく同じ目的はないと思います。 BS(来ていない)はC++オブジェクトをストリームに保存しますが、PBは読み書きする交換形式です。

PBのデータモデルははるかにシンプルです。あらゆる種類のintとfloat、文字列、配列、基本構造を取得し、それだけです。 BSでは、1つのステップですべてのオブジェクトを直接保存できます。

つまり、BSを使用すると、ネットワーク上でより多くのデータを取得できますが、すべてのオブジェクト構造を再構築する必要はありませんが、プロトコルバッファーはよりコンパクトですが、アーカイブを読み込んだ後に実行する必要がある作業が多くなります。名前が示すように、1つはプロトコル(言語に依存せず、スペース効率の良いデータの受け渡し)用であり、もう1つはシリアライゼーション(簡単なオブジェクトの保存)用です。

それで、あなたにとってより重要なのは、速度/スペース効率またはクリーンなコードですか?

44
ndfred

ミックスに追加するboost.serializationには、さらにいくつかの懸念があります。警告:ドキュメントをざっと読む以外に、プロトコルバッファを直接使用したことはありません。

boostとboost.serializationは優れていると思いますが、付属のデフォルトのアーカイブ形式はワイヤー形式には適していないという結論に達しました。

your classのバージョンを区別することが重要です(他の回答で説明されているように、boost.serializationはデータのバージョン管理をいくつかサポートしています)。異なるバージョンのシリアライゼーションライブラリ

boost.serializationの新しいバージョン 古いバージョンが逆シリアル化できるアーカイブを生成しない可能性があります(逆は当てはまりません:新しいバージョン常に古いバージョンで作成されたアーカイブをデシリアライズすることを目的としています)。これにより、次の問題が発生しました。

  • クライアントとサーバーの両方のソフトウェアが、他方が使用するシリアル化されたオブジェクトを作成するため、クライアントとサーバーの両方をロックステップでアップグレードした場合にのみ、新しいboost.serializationに移動できます。 (これは、クライアントを完全に制御できない環境では非常に困難です)。
  • Boostは共有パーツを含む1つの大きなライブラリとしてバンドルされており、シリアル化コードとBoostライブラリの他のパーツ(たとえば、shared_ptr)の両方が同じファイルで使用されている可能性があるため、アップグレードできませんboost.serializationをアップグレードできないため、boostの一部。 boostの複数のバージョンを単一の実行可能ファイルにリンクすることが可能/安全/正気であるかどうか、または古いバージョンのboostに残す必要があるビットを個別にリファクタリングする予算/エネルギーがあるかどうかわからない実行可能ファイル(この場合はDLL)。
  • スタックしている古いバージョンのboostは、使用しているコンパイラの最新バージョンをサポートしていないため、古いバージョンのコンパイラも使用しています。

グーグルは実際には プロトコルバッファーのワイヤ形式を公開する であり、ウィキペディアはそれらを 前方互換、後方互換 と説明しています(ただし、Wikipediaはプロトコルではなくデータのバージョン管理を参照していると思いますが)バッファライブラリのバージョン管理)。これらはどちらも前方互換性を保証するものではありませんが、私にはより強い示唆のように思われます。

要約すると、クライアントとサーバーをロックステップでアップグレードする機能がない場合は、プロトコルバッファーのようなよく知られている公開されたワイヤー形式を使用します。

脚注: 関連回答 の恥知らずなプラグイン。

26
bacar

Boost Serialization

  • ストリームにデータを書き込むためのライブラリです。
  • データを圧縮しません。
  • データのバージョン管理を自動的にサポートしていません。
  • sTLコンテナをサポートします。
  • 書き込まれたデータのプロパティは、選択されたストリーム(エンディアン、圧縮など)によって異なります。

プロトコルバッファ

  • インターフェースの説明からコードを生成します(C++をサポート、PythonおよびJava。C、C#など、サードパーティがサポート))。
  • オプションでデータを圧縮します。
  • データのバージョン管理を自動的に処理します。
  • プラットフォーム間のエンディアンスワッピングを処理します。
  • sTLコンテナはサポートしていません。

Boostシリアライゼーションは、オブジェクトをシリアライズされたデータのストリームに変換するためのライブラリです。プロトコルバッファは同じことを行いますが、他の作業(バージョン管理やエンディアンスワップなど)も行います。 Boostシリアライゼーションは、「小さな単純なタスク」の方が簡単です。プロトコルバッファは、おそらく「大規模インフラストラクチャ」に適しています。

編集:24-11-10:BSバージョン管理に「自動的に」追加されました。

16
Nick

ブーストシリアル化の経験はありませんが、プロトコルバッファーを使用しました。プロトコルバッファが大好きです。次の点に注意してください(これを知識なしブーストで言います)。

  • プロトコルバッファは非常に効率的であるため、私は想像しないでください。
  • プロトコルバッファは、他の言語(PythonやJava ...、その他の作業)で動作する中間表現を提供します。 C++のみを使用していることがわかっている場合は、ブーストの方が良いかもしれませんが、他の言語を使用するオプションはいいです。
  • プロトコルバッファはデータコンテナに似ています...継承などのオブジェクト指向の性質はありません。シリアル化するものの構造について考えます。
  • 「オプション」フィールドを追加できるため、プロトコルバッファは柔軟です。これは基本的に、互換性を損なうことなくプロトコルバッファの構造を変更できることを意味します。

お役に立てれば。

14
Tom

boost.serializationはC++コンパイラーを必要とするだけで、次のような構文糖を提供します

serialize_obj >> archive;
// ...
unserialize_obj << archive;

保存およびロード用。 C++が使用する唯一の言語である場合、boost.serializationに真剣なショットを与える必要があります。

私はグーグルプロトコルバッファをざっと見ました。私が見るところから、それはboost.serializationに直接匹敵するものではないと思います。 .protoファイルのコンパイラをツールチェーンに追加し、.protoファイル自体を維持する必要があります。 boost.serializationとは異なり、APIはC++に統合されません。

boost.serializationは、C++オブジェクトをシリアル化するために設計された仕事を非常にうまく行います。:) OTOH googleプロトコルバッファーのようなクエリAPIは、柔軟性を高めます。

これまではboost.serializationのみを使用していたため、パフォーマンスの比較についてコメントすることはできません。

11
Maik Beckmann

ブーストシリアライゼーションに関する上記の修正(これは その答え だと思います):

データのバージョン管理 をサポートできます。

圧縮が必要な場合-圧縮ストリームを使用してください。

エンコーディングはテキスト、バイナリ、XMLのいずれかであるため、プラットフォーム間のエンディアンスワッピングを処理できます。

7
Robert Ramey

Boostのライブラリを使用して何も実装したことはありませんが、Googleのprotobuffの方が考え抜かれており、コードがはるかに簡潔で読みやすくなっています。一緒に使用したいさまざまな言語を見て、コードとドキュメントを読んで決めてください。

私がprotobufで直面した1つの問題は、生成されたコードGetMessage()で非常に一般的に使用される関数に名前が付けられたことです。もちろん、これはWin32 GetMessageマクロと競合します。

Protobufを強くお勧めします。彼らは非常に便利です。

5
i_am_jorf

エンジニアリングのほとんどすべてと同じように、私の答えは...「場合によります」です。

どちらも十分にテストされ、吟味されたテクノロジーです。どちらもデータを取得して、どこかに送信するのに適したものに変換します。どちらもおそらく十分高速であり、実際にバイトを数えているのであれば、おそらくどちらにも満足できないでしょう(作成された両方のパケットがXMLまたはJSONのごく一部になることに注意してください)。

私にとって、それは本当にワークフローにかかっていますし、反対側でC++以外のものが必要かどうかも問題です。

最初にメッセージの内容を把握し、システムを最初から構築する場合は、プロトコルバッファを使用します。メッセージを抽象的な方法で考えると、任意の言語でコードを自動生成できます(サードパーティのプラグインは、ほぼすべてのものが利用可能です)。また、プロトコルバッファを使用すると、コラボレーションが簡素化されます。 .protoファイルを送信するだけで、他のチームはどのデータが転送されているかを明確に把握できます。私も彼らに何も課しません。 Javaを使用したい場合は、先に進んでください。

私がすでにC++でクラスを構築していて(これが頻繁に発生していることです)、そのデータをネットワーク経由で送信したい場合は、Boost Serializationが明らかに役立ちます(特に、他の場所にすでにBoost依存関係がある場合)。 )。

2
It'sPete

これは古い質問であることはわかっていますが、2ペンスを投入すると思いました。

ブーストを使用すると、クラスにデータ検証を書く機会があります。データ定義と有効性のチェックがすべて1か所にあるため、これは適切です。

GPBでできる最善のことは、.protoファイルにコメントを入れ、それを使用している人がそれを読んで注意を払い、妥当性チェック自体を実装するすべての希望に反することです。

言うまでもなく、ネットワークストリームの反対側にいる他の誰かに頼って、自分と同じ勢いでこれを行う場合は、これは起こりにくく、信頼できません。さらに、有効性の制約が変更される場合、複数のコード変更を計画、調整、実行する必要があります。

したがって、GPBは、すべてのチームメンバーと定期的に会って話をする機会がほとんどない開発には不適切であると考えています。

==編集==

私が言っているのは、これです。

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)

これの第13章を見てください [〜#〜] pdf [〜#〜] ;あなたができることは驚くべきことです。

配列も制約できます:

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(真新しい、ツールサポートはまだ開発中)

プラス他。

最後の2つに注意してください。はい、ASN.1でデータ構造を定義し、コードを生成し、XMLおよびJSONでメッセージを送信/消費できます。 1980年代に始まったテクノロジーにとっては悪くない。

バージョン管理は、GPBとは異なる方法で行われます。拡張を許可することができます:

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

つまり、後日、Fooに追加できるようになり、このバージョンを持つ古いシステムは引き続き機能します(ただし、bearingフィールドにしかアクセスできません)。

私はASN.1を非常に高く評価しています。対処するのが面倒な場合があります(ツールに費用がかかる可能性がある、生成されたコードが必ずしも美しいとは限らないなど)。しかし、この制約は本当に素晴らしい機能であり、何度も何度も心の痛みを軽減できました。エンコーダー/デコーダーがダフデータを生成したことを報告すると、開発者に多くのことを言わせます。

その他のリンク:

観察

データを共有するには:

  • コードの最初のアプローチ(例:Boostシリアライゼーション)で元の言語(例:C++)に制限するか、別の言語で多くの追加作業を強いる
  • 最初のスキーマの方が優れていますが、
    • これらの多くは、共有契約に大きなギャップを残しています(つまり、制約はありません)。 GPBは他の点では非常に優れているため、この点で迷惑です。
    • 一部には制約(XSD、JSONなど)がありますが、パッチツールのサポートが必要です。
    • たとえば、Microsoftのxsd.exeは、xsdファイルの制約を積極的に無視します(MSの言い訳は本当に微妙です)。 XSDは(制約の観点から)良いですが、他の人がそれらを強制する優れたXSDツールを使用することを信頼できない場合、XSDの価値は低下します。
    • JSONバリデーターは大丈夫ですが、そもそもJSONを作成するのに役立つものではなく、自動的に呼び出されるわけではありません。 JSONメッセージを送信する誰かがそれをバリデーターに通したという保証はありません。自分で検証することを忘れないでください。
    • ASN.1ツールはすべて制約チェックを実装しているようです。

したがって、私にとっては、ASN.1がそれを行います。これは、他の人が間違いを犯す可能性が最も低いものです。これは、適切な機能を備えたツールであり、すべてのツールがそれらの機能を完全に実装するように見えるため、ほとんどの目的にとって十分言語に依存しないためです。

正直なところ、GPBが勝者になる制約メカニズムを追加した場合。 XSDは近いですが、ツールはほとんど普遍的なゴミです。他の言語のまともなコードジェネレーターがあった場合、JSONスキーマはかなり良いでしょう。

GPBに制約が追加されている場合(注:これはワイヤ形式を変更しません)、ほとんどすべての目的のために私がすべての人に推奨するものです。ただし、ASN.1のuPERは無線リンクに非常に役立ちます。

0
bazza

ブーストシリアライゼーションを「実際の」ドメインオブジェクトと緊密に組み合わせて使用​​し、オブジェクト階層全体を継承(継承)できます。 Protobufは継承をサポートしていないため、集計を使用する必要があります。 Protobufはコアドメインオブジェクト自体ではなく、DTO(データ転送オブジェクト)に使用する必要があると人々は主張しています。 boost :: serializationとprotobufの両方を使用しました。 boost :: serializationのパフォーマンスを考慮に入れる必要があります cereal を使用することもできます。

0
Amanjit Gill