wake-up-neo.com

serialisierung im Vergleich zu Google-Protokollpuffern?

Hat jemand, der Erfahrung mit diesen Bibliotheken hat, irgendeinen Kommentar, welchen sie bevorzugen? Gab es Leistungsunterschiede oder Schwierigkeiten bei der Verwendung?

62
0xC0DEFACE

Ich habe ein bisschen mit beiden Systemen herumgespielt, nichts Ernstes, nur ein paar einfache Hacksachen, aber ich hatte das Gefühl, dass es einen Unterschied gibt, wie man die Bibliotheken verwenden soll.

Mit boost :: serialization schreiben Sie zuerst Ihre eigenen Strukturen/Klassen und fügen dann die Archivierungsmethoden hinzu. Es bleiben jedoch einige ziemlich "schlanke" Klassen übrig, die als vererbte Datenelemente verwendet werden können.

Bei Protokollpuffern ist die Menge des für eine einfache Struktur generierten Codes ziemlich groß, und die generierten Strukturen und der Code sind eher für den Betrieb gedacht, und Sie verwenden die Funktionalität der Protokollpuffer, um Daten zu und von Ihren eigenen internen Strukturen zu transportieren .

29

Ich benutze Boost-Serialisierung schon lange und habe mich nur in Protokollpuffer eingegraben, und ich denke, sie haben nicht genau den gleichen Zweck. BS (hat das nicht kommen sehen) speichert Ihre C++ - Objekte in einem Stream, wohingegen PB ein Austauschformat ist, in das Sie lesen.

Das Datenmodell von PB ist viel einfacher: Sie erhalten alle Arten von Ints und Floats, Strings, Arrays und die grundlegende Struktur. Mit BS können Sie alle Ihre Objekte in einem Schritt direkt speichern.

Mit BS erhalten Sie also mehr Daten auf der Leitung, aber Sie müssen nicht alle Objektstrukturen neu erstellen, während Protokollpuffer kompakter sind, nach dem Lesen des Archivs jedoch noch mehr Arbeit zu erledigen ist. Wie der Name schon sagt, ist eines für Protokolle (sprachunabhängige, platzsparende Datenübergabe), das andere für die Serialisierung (unkomplizierte Speicherung von Objekten).

Was ist für Sie wichtiger: Geschwindigkeits-/Platzeffizienz oder sauberer Code?

43
ndfred

Es gibt ein paar zusätzliche Bedenken bezüglich boost.serialization, die ich dem Mix hinzufügen möchte. Vorbehalt: Ich habe keine direkten Erfahrungen mit Protokollpuffern, außer mit dem Durchsuchen der Dokumente.

Beachten Sie, dass, obwohl ich denke, dass boost und boost.serialization bei dem, was es tut, großartig ist, ich zu dem Schluss gekommen bin, dass die Standard-Archivformate, mit denen es kommt, keine gute Wahl für ein Drahtformat sind.

Es ist wichtig, zwischen den Versionen von Ihrer Klasse (wie in anderen Antworten erwähnt, dass boost.serialization etwas für die Versionierung von Daten unterstützt) und der Kompatibilität zwischen verschiedenen Versionen der Serialisierungsbibliothek zu unterscheiden.

Neuere Versionen von boost.serialization generiert möglicherweise keine Archive, die ältere Versionen deserialisieren können . (das Gegenteil trifft nicht zu: neuere Versionen dienen immer dazu, Archive älterer Versionen zu deserialisieren). Dies hat zu folgenden Problemen für uns geführt:

  • Sowohl unsere Client- als auch die Server-Software erstellen serialisierte Objekte, die die andere verwendet. Daher können wir nur zu einer neueren boost.serialization wechseln, wenn wir sowohl Client als auch Server in Lockstep aktualisieren. (Dies ist eine ziemliche Herausforderung in einer Umgebung, in der Sie nicht die volle Kontrolle über Ihre Kunden haben).
  • Boost wird als eine große Bibliothek mit gemeinsam genutzten Teilen gebündelt geliefert, und sowohl der Serialisierungscode als auch die anderen Teile der Boost-Bibliothek (z. B. shared_ptr) können in derselben Datei verwendet werden. Ich kann keine Teile von boost aktualisieren weil ich boost.serialization nicht aktualisieren kann. Ich bin nicht sicher, ob es möglich/sicher/vernünftig ist, zu versuchen, mehrere Versionen von Boost in einer einzigen ausführbaren Datei zu verknüpfen, oder ob wir über das Budget/die Energie verfügen, um Bits herauszufällen, die auf einer älteren Boost-Version verbleiben müssen, in eine separate ausführbare Datei (DLL in unserem Fall).
  • Die alte Version von Boost, an der wir festhalten, unterstützt nicht die neueste Version des von uns verwendeten Compilers. Daher bleiben wir auch bei einer alten Version des Compilers.

Google scheint tatsächlich das Protokollpuffer-Drahtformat zu veröffentlichen , und Wikipedia beschreibt sie als vorwärtskompatibel, abwärtskompatibel (obwohl ich denke, Wikipedia bezieht sich auf die Datenversionierung und nicht auf die Protokollpufferbibliothek) Versionierung). Obwohl keines davon eine Garantie für die Vorwärtskompatibilität darstellt, scheint es mir ein stärkeres Zeichen zu sein.

Zusammenfassend kann ich sagen, dass ich ein bekanntes, veröffentlichtes Wire-Format wie Protokollpuffer bevorzugen würde, wenn ich nicht in der Lage bin, Client und Server in Lockstep zu aktualisieren.

Fußnote: schamloser Plug für ein verwandte Antwort von mir.

25
bacar

Boost-Serialisierung

  • ist eine Bibliothek zum Schreiben von Daten in einen Stream.
  • komprimiert keine Daten.
  • unterstützt keine automatische Versionsverwaltung von Daten. 
  • unterstützt STL-Container.
  • die Eigenschaften der geschriebenen Daten hängen von den gewählten Streams ab (z. B. Endian, komprimiert).

Protokollpuffer

  • generiert Code aus der Schnittstellenbeschreibung (unterstützt standardmäßig C++, Python und Java. C, C # und andere von Drittanbietern).
  • komprimiert optional Daten.
  • behandelt die Versionierung von Daten automatisch.
  • behandelt den Endian-Austausch zwischen Plattformen.
  • unterstützt keine STL-Container.

Boost-Serialisierung ist eine Bibliothek zum Konvertieren eines Objekts in einen serialisierten Datenstrom. Protokollpuffer machen dasselbe, erledigen aber auch andere Aufgaben (wie Versionierung und Endian-Swapping). Boost-Serialisierung ist einfacher für "kleine einfache Aufgaben". Protokollpuffer sind wahrscheinlich besser für "größere Infrastruktur".

EDIT: 24-11-10: "automatisch" zur BS-Versionierung hinzugefügt.

16
Nick

Ich habe keine Erfahrung mit Boost-Serialisierung, aber ich habe Protokollpuffer verwendet. Ich mag Protokollpuffer sehr. Beachten Sie Folgendes (ich sage dies mit ohne Kenntnis von Boost).

  • Protokollpuffer sind sehr effizient, daher stelle ich mir nicht vor, dass dies ein ernstes Problem gegenüber Boost ist .
  • Protokollpuffer bieten eine Zwischendarstellung, die mit anderen Sprachen funktioniert (Python und Java ... und mehr in Arbeit). Wenn Sie wissen, dass Sie nur C++ verwenden, ist boost vielleicht besser, aber die Option, andere Sprachen zu verwenden, ist Nice.
  • Protokollpuffer sind eher wie Datencontainer ... es gibt keine objektorientierte Natur, wie z. B. Vererbung. Denken Sie an die Struktur dessen, was Sie serialisieren möchten.
  • Protokollpuffer sind flexibel, da Sie "optionale" Felder hinzufügen können. Dies bedeutet im Grunde, dass Sie die Struktur des Protokollpuffers ändern können, ohne die Kompatibilität zu beeinträchtigen.

Hoffe das hilft.

14
Tom

boost.serialization benötigt nur den C++ - Compiler und gibt Ihnen etwas Syntaxzucker

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

zum Speichern und Laden. Wenn nur C++ verwendet wird, sollten Sie boost.serialization eine ernsthafte Chance geben. 

Ich habe mir kurz die Google-Protokollpuffer angesehen. Von dem, was ich sehe, würde ich sagen, dass es nicht direkt mit boost.serialization vergleichbar ist. Sie müssen der Toolchain einen Compiler für die .proto-Dateien hinzufügen und die .proto-Dateien selbst verwalten. Die API lässt sich nicht wie Boost.serialization in C++ integrieren. 

boost.serialization erledigt seine Aufgabe sehr gut: zum Serialisieren von C++ - Objekten :) OTOH Eine Abfrage-API wie die Google-Protokollpuffer bietet Ihnen mehr Flexibilität.

Da ich bisher nur boost.serialization verwendet habe, kann ich den Leistungsvergleich nicht kommentieren. 

11
Maik Beckmann

Korrektur nach oben (denke mal, das ist diese Antwort ) über Boost Serialization:

Es erlaubt die Unterstützung von Datenversionierung .

Wenn Sie eine Komprimierung benötigen, verwenden Sie einen komprimierten Stream.

Kann Endian-Swapping zwischen Plattformen verarbeiten, da die Kodierung Text, Binär oder XML sein kann.

7
Robert Ramey

Ich habe nie etwas mit der Bibliothek von boost implementiert, aber ich fand die Protobuff von Google durchdachter und der Code ist viel sauberer und einfacher zu lesen. Ich würde vorschlagen, die verschiedenen Sprachen, mit denen Sie es verwenden möchten, anzusehen, den Code und die Dokumentation durchzulesen und sich zu entscheiden.

Die einzige Schwierigkeit, die ich mit Protobufs hatte, war, dass sie in ihrem generierten Code GetMessage () eine häufig verwendete Funktion benannten, die natürlich mit dem Win32-GetMessage-Makro in Konflikt steht. 

Ich würde Protobufs trotzdem wärmstens empfehlen. Sie sind sehr nützlich.

5
i_am_jorf

Wie bei fast allem in der Technik lautet meine Antwort ... "es kommt darauf an."

Beide sind gut erprobte, geprüfte Technologien. Beide nehmen Ihre Daten in etwas freundliches auf, um sie irgendwo zu senden. Beide werden wahrscheinlich schnell genug sein, und wenn Sie wirklich ein Byte hier oder dort zählen, werden Sie wahrscheinlich mit keinem zufrieden sein (seien wir ehrlich, beide erstellten Pakete sind ein kleiner Bruchteil von XML oder JSON).

Für mich kommt es wirklich auf den Workflow an und ob Sie am anderen Ende etwas anderes als C++ benötigen.

Wenn Sie den Inhalt Ihrer Nachricht zuerst herausfinden möchten und ein System von Grund auf neu erstellen, verwenden Sie Protokollpuffer. Sie können sich die Nachricht abstrakt vorstellen und dann den Code automatisch in der gewünschten Sprache generieren (Plugins von Drittanbietern sind für fast alles verfügbar). Ich finde auch die Zusammenarbeit mit Protocol Buffers vereinfacht. Ich schicke einfach eine .proto-Datei und dann hat das andere Team eine klare Vorstellung davon, welche Daten übertragen werden. Ich lege ihnen auch nichts auf. Wenn sie Java verwenden wollen, machen Sie weiter!

Wenn ich bereits eine Klasse in C++ erstellt habe (und dies ist öfter passiert als nicht) und ich diese Daten jetzt über die Leitung senden möchte, ist die Boost-Serialisierung offensichtlich sehr sinnvoll (vor allem, wenn ich bereits an anderer Stelle eine Boost-Abhängigkeit habe.) ).

2
It'sPete

Ich weiß, dass dies jetzt eine ältere Frage ist, aber ich dachte, ich würde meine 2 Pence hineinwerfen!

Mit boost erhalten Sie die Möglichkeit, Daten in Ihre Klassen zu schreiben. Dies ist gut, weil die Datendefinition und die Gültigkeitsprüfung alle an einem Ort liegen. 

Mit GPB können Sie am besten Kommentare in die .proto-Datei einfügen und hoffen, dass alle, die es verwenden, es lesen, darauf achten und die Gültigkeitsprüfungen selbst implementieren. 

Es ist unnötig zu erwähnen, dass dies unwahrscheinlich und unzuverlässig ist, wenn Sie sich auf eine andere Person am anderen Ende eines Netzwerk-Streams verlassen, um dies mit derselben Kraft wie sich selbst zu tun. Wenn sich die Bedingungen für die Gültigkeit ändern, müssen außerdem mehrere Codeänderungen geplant, koordiniert und durchgeführt werden. 

Ich halte GPB daher für ungeeignet für Entwicklungen, bei denen es wenig Gelegenheit gibt, regelmäßig mit allen Teammitgliedern zu sprechen und sich mit ihnen zu unterhalten. 

== BEARBEITEN ==

Was ich damit meine, ist:

message Foo
{
    int32 bearing = 1;
}

Nun, wer soll sagen, was der gültige Bereich von bearing ist? Wir können haben

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

Aber das hängt davon ab, dass jemand anderes dies liest und Code schreibt. Wenn Sie es beispielsweise bearbeiten, wird die Einschränkung wie folgt:

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

sie sind völlig abhängig von jedem Benutzer, der diese .proto-Software verwendet hat, um den Code zu aktualisieren. Das ist unzuverlässig und teuer.

Zumindest bei der Boost-Serialisierung verteilen Sie eine einzelne C++ - Klasse, und das kann die Gültigkeitsprüfung von Daten direkt beinhalten. Wenn sich diese Einschränkungen ändern, muss niemand sonst etwas tun, außer sicherzustellen, dass er dieselbe Version des Quellcodes verwendet wie Sie.

Alternative

Es gibt eine Alternative: ASN.1. Dies ist uralt, hat aber einige wirklich sehr nützliche Dinge:

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

Beachten Sie die Einschränkung. Wenn also jemand diese .asn-Datei verwendet, um Code zu generieren, erhält er Code, der automatisch überprüft, ob bearing zwischen 0 und 359 liegt. Wenn Sie die .asn-Datei aktualisieren, 

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

sie müssen nur neu kompilieren. Es sind keine weiteren Codeänderungen erforderlich.

Sie können auch tun:

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

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

Beachten Sie den <. In den meisten Werkzeugen können auch LagerMin und LagerMax als Konstanten im generierten Code erscheinen. Das ist äußerst nützlich.

Einschränkungen können sehr aufwendig sein:

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

Schauen Sie sich Kapitel 13 in diesem PDF an; Es ist erstaunlich, was du tun kannst.

Arrays können auch eingeschränkt werden:

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 ist altmodisch, aber immer noch aktiv entwickelt, weit verbreitet (Ihr Mobiltelefon verwendet es häufig) und ist weitaus flexibler als die meisten anderen Serialisierungstechnologien. Der einzige Mangel, den ich sehen kann, ist, dass es keinen anständigen Code-Generator für Python gibt. Wenn Sie C/C++, C #, Java, ADA verwenden, sind Sie mit einer Mischung aus kostenlosen (C/C++, ADA) und kommerziellen Tools (C/C++, C #, Java) gut bedient. 

Besonders gut gefällt mir die große Auswahl an binären und textbasierten Drahtformaten. Dies macht es in einigen Projekten äußerst praktisch. Die Liste der Drahtformate enthält derzeit:

  • BER (binär) 
  • PER (binär, ausgerichtet und nicht ausgerichtet. Dies ist extrem biteffizient. Zum Beispiel, und INTEGER, die zwischen 0 und 15 eingeschränkt sind, beanspruchen nur 4 bits auf der Leitung.) 
  • OER 
  • DER (ein anderes binäres) 
  • XML (auch XER) 
  • JSON (brandneue Tool-Unterstützung entwickelt sich noch)

plus andere.

Beachten Sie die letzten beiden? Ja, Sie können Datenstrukturen in ASN.1 definieren, Code generieren und Meldungen in XML und JSON ausgeben/verbrauchen. Nicht schlecht für eine Technologie, die in den 80er Jahren begann.

Die Versionierung erfolgt anders als GPB. Sie können Erweiterungen berücksichtigen:

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

Das bedeutet, dass ich zu einem späteren Zeitpunkt Foo hinzufügen kann und ältere Systeme, auf denen diese Version installiert ist, noch funktionieren können (aber nur auf das Feld bearing zugreifen können).

Ich schätze ASN.1 sehr hoch. Es kann schwierig sein, damit umzugehen (Werkzeuge könnten Geld kosten, der generierte Code ist nicht unbedingt schön usw.). Aber die Einschränkungen sind ein wirklich fantastisches Feature, das mir immer wieder jede Menge Herzschmerz erspart hat. Die Entwickler schreien viel, wenn die Encoder/Decoder melden, dass sie Duff-Daten generiert haben.

Andere Links:

Beobachtungen

Daten freigeben:

  • Ansätze für den ersten Code (z. B. Boost-Serialisierung) beschränken Sie auf die Originalsprache (z. B. C++) oder zwingen Sie, eine Menge zusätzlicher Arbeit in einer anderen Sprache auszuführen
  • Schema zuerst ist besser, aber
    • Viele von ihnen hinterlassen große Lücken im Freigabevertrag (d. H. Keine Einschränkungen). GPB ist diesbezüglich ärgerlich, weil es sonst sehr gut ist.Einige haben Einschränkungen (z. B. XSD, JSON), werden jedoch von unvollständigen Tools unterstützt.
    • Beispielsweise ignoriert die xsd.exe von Microsoft aktiv die Einschränkungen in den xsd-Dateien (die Entschuldigung von MS ist wirklich schwach). XSD ist gut (aus der Sicht der Einschränkungen), aber wenn Sie nicht darauf vertrauen können, dass der andere ein gutes XSD-Tool verwendet, das sie für ihn/sie erzwingt, wird der Wert von XSD verringert 
    • JSON-Validatoren sind in Ordnung, aber sie helfen Ihnen nicht beim Erstellen des JSONs und werden nicht automatisch aufgerufen. Es kann nicht garantiert werden, dass jemand, der Ihnen eine JSON-Nachricht sendet, diese durch einen Prüfer geleitet hat. Sie müssen daran denken, es selbst zu bestätigen.
    • Alle ASN.1-Tools scheinen die Einschränkungen zu implementieren.
    • ASN.1 macht es also für mich. Es ist derjenige, der am wenigsten dazu führt, dass jemand anderes einen Fehler macht, denn er ist derjenige mit den richtigen Funktionen und die Tools sind scheinbar bestrebt, diese Features vollständig zu implementieren, und sie sind für die meisten Zwecke sprachneutral genug. 

Um ehrlich zu sein, wenn GPB einen Zwangsmechanismus hinzufügt, wäre das der Gewinner. XSD ist nahe, aber die Werkzeuge sind fast überall Müll. Wenn es anständige Codegeneratoren für andere Sprachen gibt, wäre das JSON-Schema ziemlich gut.

Wenn GPB Einschränkungen hinzugefügt hätte (Hinweis: Dies würde keine der Drahtformate ändern), würde ich das für fast jeden Zweck jedem empfehlen. Obwohl ASN.1 uPER für Funkverbindungen sehr nützlich ist. 

If GPB had constraints added (note: this would not change any of the wire formats), that'd be the one I'd recommend to everyone for almost every purpose. Though ASN.1's uPER is very useful for radio links.

0
bazza

Sie können die Boost-Serialisierung in enger Verbindung mit Ihren "echten" Domänenobjekten verwenden und die gesamte Objekthierarchie (Vererbung) serialisieren. Protobuf unterstützt keine Vererbung, daher müssen Sie die Aggregation verwenden. Die Leute argumentieren, dass Protobuf für DTOs (Datenübertragungsobjekte) und nicht für Kerndomänenobjekte selbst verwendet werden sollte. Ich habe sowohl boost :: serialization als auch protobuf verwendet. Die Leistung von boost :: serialization sollte berücksichtigt werden, cereal könnte eine Alternative sein. 

0
Amanjit Gill