protocol protobuf google buffers c++ performance serialization protocol-buffers boost-serialization

c++ - protobuf - impulsar la serialización vs buffers de protocolo de google?



protobuf python (11)

Como con casi todo en ingeniería, mi respuesta es ... "depende".

Ambas son tecnologías probadas y bien probadas. Ambos tomarán sus datos y los convertirán en algo amigable para enviar a algún lugar. Es probable que ambos sean lo suficientemente rápidos, y si realmente estás contando un byte aquí o allá, probablemente no seas feliz con ninguno de los dos (los paquetes creados serán una pequeña fracción de XML o JSON).

Para mí, todo se reduce al flujo de trabajo y si necesitas algo más que C ++ en el otro extremo.

Si quiere averiguar primero el contenido de su mensaje y está construyendo un sistema desde cero, use Buffers de protocolo. Puede pensar en el mensaje de forma abstracta y luego generar automáticamente el código en el idioma que desee (los complementos de terceros están disponibles para casi todo). Además, encuentro la colaboración simplificada con los Protocolos de protocolo. Simplemente envío un archivo .proto y luego el otro equipo tiene una idea clara de qué datos se están transfiriendo. Tampoco les impongo nada. Si quieren usar Java, ¡adelante!

Si ya he construido una clase en C ++ (y esto ha sucedido más de las veces) y quiero enviar esos datos por cable ahora, Boost Serialization obviamente tiene muchísimo sentido (especialmente cuando ya tengo una dependencia de Boost en otro lado) )

¿Alguien con experiencia en estas bibliotecas tiene algún comentario sobre cuál prefiere? ¿Hubo alguna diferencia de rendimiento o dificultades en el uso?


Corrección a lo anterior (supongo que esta es la respuesta ) sobre la Serialización de Boost:

SÍ permite el control de versiones de datos .

Si necesita compresión, use una transmisión comprimida.

Puede manejar el intercambio endian entre plataformas ya que la codificación puede ser de texto, binario o XML.


Hay un par de preocupaciones adicionales con la optimización de boost que agregaré a la mezcla. Advertencia: no tengo ninguna experiencia directa con los búferes de protocolo más allá de rozar los documentos.

Tenga en cuenta que si bien creo que boost, y boost.serialization, es excelente en lo que hace, he llegado a la conclusión de que los formatos de archivo predeterminados con los que viene no son una gran opción para un formato de conexión.

Es importante distinguir entre las versiones de su clase (como se menciona en otras respuestas, boost.serialization tiene algún soporte para el control de versiones de datos) y la compatibilidad entre las diferentes versiones de la biblioteca de serialización .

Es posible que las versiones más recientes de boost.serialization no generen archivos que las versiones anteriores puedan deserializar . (Lo contrario no es cierto: las versiones más nuevas siempre están destinadas a deserializar los archivos creados por versiones anteriores). Esto nos ha llevado a los siguientes problemas:

  • Tanto nuestro cliente como el software del servidor crean objetos serializados que el otro consume, por lo que solo podemos pasar a una nueva actualización de boost.serialization si actualizamos el cliente y el servidor en bloque. (Esto es todo un desafío en un entorno donde no tienes el control total de tus clientes).
  • Boost viene incluido como una gran biblioteca con partes compartidas, y tanto el código de serialización como otras partes de la biblioteca de impulso (ej. Shared_ptr) pueden estar en uso en el mismo archivo, no puedo actualizar partes de boost porque puedo '' t actualización boost.serialization. No estoy seguro si es posible / seguro / sensato intentar vincular múltiples versiones de refuerzo en un único ejecutable, o si tenemos el presupuesto / energía para refactorizar los bits que deben permanecer en una versión anterior de impulsar en un archivo separado ejecutable (DLL en nuestro caso).
  • La versión anterior de boost en la que estamos estancados no es compatible con la última versión del compilador que usamos, por lo que también estamos atascados en una versión anterior del compilador.

Google parece publicar realmente el formato de cableado de búferes de protocolo , y Wikipedia los describe como compatibles con versiones anteriores, compatibles con versiones anteriores (aunque creo que Wikipedia se refiere al control de versiones de datos en lugar del control de versiones de la biblioteca de búfer de protocolo). Si bien ninguno de estos es una garantía de compatibilidad con versiones anteriores, parece una indicación más fuerte para mí.

En resumen, preferiría un formato de cable conocido y publicado, como búferes de protocolo, cuando no tengo la capacidad de actualizar cliente y servidor en bloque.

Nota al pie: plug sin vergüenza para una respuesta relacionada por mí.


He estado utilizando Boost Serialization durante mucho tiempo y simplemente busqué en búferes de protocolo, y creo que no tienen exactamente el mismo propósito. BS (no lo veía venir) guarda sus objetos C ++ en una secuencia, mientras que PB es un formato de intercambio desde / desde el que lee.

El modelo de datos de PB es mucho más simple: se obtienen todo tipo de entradas y flotantes, cadenas, matrices, estructura básica y eso es todo. BS le permite guardar directamente todos sus objetos en un solo paso.

Eso significa que con BS obtendrás más datos en el cable pero no tienes que reconstruir toda la estructura de tus objetos, mientras que los buffers de protocolo son más compactos, pero hay más trabajo por hacer después de leer el archivo. Como su nombre lo indica, uno es para protocolos (paso de datos eficientes desde el punto de vista del lenguaje) y el otro para la serialización (ahorro de objetos sin formato).

Entonces, ¿qué es más importante para usted: eficiencia de velocidad / espacio o código limpio?


He jugado un poco con ambos sistemas, nada serio, solo algunas cosas simples de hack, pero sentí que hay una diferencia real en cómo se supone que debes usar las bibliotecas.

Con boost :: serialization, primero escribes tus propias estructuras / clases y luego agregas los métodos de archivo, pero aún te quedan algunas clases bastante "delgadas", que se pueden usar como miembros de datos, heredadas, lo que sea.

Con los búferes de protocolo, la cantidad de código generado incluso para una estructura simple es bastante sustancial, y las estructuras y el código que se generan están más destinados a funcionar, y que usa la funcionalidad de búfers de protocolo para transportar datos hacia y desde sus propias estructuras internas .


No tengo experiencia con la serialización de impulso, pero he usado búferes de protocolo. Me gustan mucho los búferes de protocolo. Tenga en cuenta lo siguiente (digo esto sin conocimiento de impulso).

  • Los búferes de protocolo son muy eficientes, así que no me imagino que sea un problema serio frente a un impulso.
  • Los búferes de protocolo proporcionan una representación intermedia que funciona con otros lenguajes (Python y Java ... y más en las obras). Si sabes que solo estás usando C ++, tal vez impulsar es mejor, pero la opción de utilizar otros idiomas es agradable.
  • Los búferes de protocolo son más como contenedores de datos ... no hay naturaleza orientada a objetos, como la herencia. Piense en la estructura de lo que quiere serializar.
  • Los búferes de protocolo son flexibles porque puede agregar campos "opcionales". Esto básicamente significa que puede cambiar la estructura del búfer de protocolo sin romper la compatibilidad.

Espero que esto ayude.


Nunca implementé nada usando la biblioteca de boost, pero encontré que Google protobuff es más pensado, y el código es mucho más limpio y fácil de leer. Sugiero que eche un vistazo a los distintos idiomas con los que desea utilizarlo y lea el código y la documentación, y tome una decisión.

La única dificultad que tuve con protobufs fue que denominaron a una función muy utilizada en su código generado GetMessage (), que por supuesto entra en conflicto con la macro Win32 GetMessage.

Todavía recomendaría protobufs. Son muy útiles.


Puede usar la serialización de refuerzo en conjunción estrecha con sus objetos de dominio "reales" y serializar la jerarquía completa de objetos (herencia). Protobuf no es compatible con la herencia, por lo que deberá usar la agregación. La gente argumenta que Protobuf debe usarse para DTO (objetos de transferencia de datos), y no para objetos de dominio central. He usado tanto boost :: serialization y protobuf. El rendimiento de boost :: serialización debe tenerse en cuenta, el cereal podría ser una alternativa.


Sé que esta es una pregunta más antigua ahora, ¡pero pensé en arrojar mis 2 peniques!

Con impulso, tienes la oportunidad de escribir algunas validaciones de datos en tus clases; esto es bueno porque la definición de datos y las verificaciones de validez están todas en un solo lugar.

Con GPB, lo mejor que puede hacer es colocar comentarios en el archivo .proto y esperar, contra toda esperanza, que quien lo esté usando lo lea, le preste atención e implemente los controles de validez.

Huelga decir que esto es poco probable y poco confiable si confía en alguien más en el otro extremo de la red para hacer esto con el mismo vigor que uno mismo. Además, si cambian las restricciones de validez, se deben planear, coordinar y llevar a cabo varios cambios de código.

Por lo tanto, considero que GPB es inapropiado para desarrollos en los que hay pocas oportunidades de reunirse regularmente y hablar con todos los miembros del equipo.

== EDITAR ==

El tipo de cosas que quiero decir es esto:

message Foo { int32 bearing = 1; }

Ahora, ¿quién dice cuál es el rango de bearing válido? Podemos tener

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

Pero eso depende de que alguien más lea esto y escriba un código para ello. Por ejemplo, si lo edita y la restricción se convierte en:

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

usted es completamente dependiente de todos los que han usado este .proto actualizando su código. Eso no es confiable y costoso.

Al menos con la serialización de Boost está distribuyendo una sola clase de C ++, y eso puede tener incorporadas verificaciones de validez de datos. Si esas restricciones cambian, entonces nadie más necesita hacer otro trabajo que no sea asegurarse de que estén usando la misma versión del código fuente que usted.

Alternativa

Hay una alternativa: ASN.1. Esto es antiguo, pero tiene algunas cosas realmente útiles:

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

Tenga en cuenta la restricción. Entonces, cada vez que alguien consume este archivo .asn, genera código, termina con un código que verifica automáticamente que el bearing esté entre 0 y 359. Si actualiza el archivo .asn,

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

todo lo que necesitan hacer es recompilar. No se requieren otros cambios de código.

También puedes hacer:

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

Tenga en cuenta el < . Y también en la mayoría de las herramientas, el bearingMin y bearingMax pueden aparecer como constantes en el código generado. Eso es extremadamente útil.

Las restricciones pueden ser bastante elaboradas:

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

Mira el Capítulo 13 en este PDF ; es increíble lo que puedes hacer;

Las matrices también pueden estar restringidas:

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 está pasado de moda, pero todavía se desarrolla activamente, se usa ampliamente (su teléfono móvil lo usa mucho) y es mucho más flexible que la mayoría de las otras tecnologías de serialización. La única deficiencia que puedo ver es que no hay un generador de código decente para Python. Si está usando C / C ++, C #, Java, ADA, entonces cuenta con una buena combinación de herramientas gratuitas (C / C ++, ADA) y comerciales (C / C ++, C #, JAVA).

Me gusta especialmente la gran variedad de formatos de alambre binarios y basados ​​en texto. Esto lo hace extremadamente conveniente en algunos proyectos. La lista de wireformat actualmente incluye:

  • BER (binario)
  • PER (binario, alineado y desalineado. Esto es extremadamente eficiente en cuanto a los bits. Por ejemplo, INTEGER limitado entre 0 y 15 solo ocupará 4 bits en el cable)
  • REA
  • DER (otro binario)
  • XML (también XER)
  • JSON (nuevo soporte de herramientas todavía está en desarrollo)

más otros.

Tenga en cuenta los dos últimos? Sí, puede definir estructuras de datos en ASN.1, generar código y emitir / consumir mensajes en XML y JSON. No está mal para una tecnología que comenzó en la década de 1980.

El control de versiones se realiza de forma diferente a GPB. Puede permitir extensiones:

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

Esto significa que en una fecha posterior puedo agregar a Foo , y los sistemas más antiguos que tienen esta versión todavía pueden funcionar (pero solo pueden acceder al campo de bearing ).

Califico ASN.1 muy alto. Puede ser difícil de manejar (las herramientas pueden costar dinero, el código generado no es necesariamente hermoso, etc.). Pero las limitaciones son una característica realmente fantástica que me ha ahorrado una tonelada de dolor de corazón una y otra vez. Hace que los desarrolladores se quejen mucho cuando los codificadores / decodificadores informan que generaron datos duff.

Otros enlaces:

Observaciones

Para compartir datos:

  • Los primeros enfoques del código (p. Ej., La serialización de Boost) lo restringen al idioma original (p. Ej., C ++) u le obligan a realizar un trabajo adicional en otro idioma.
  • Schema primero es mejor, pero
    • Muchos de estos dejan grandes lagunas en el contrato de intercambio (es decir, sin restricciones). GPB es molesto en este sentido, porque de lo contrario es muy bueno.
    • Algunos tienen restricciones (por ejemplo, XSD, JSON), pero sufren un soporte desigual de la herramienta.
    • Por ejemplo, el xsd.exe de Microsoft ignora activamente las restricciones en los archivos xsd (la excusa de MS es realmente débil). XSD es bueno (desde el punto de vista de las restricciones), pero si no puedes confiar en que el otro chico use una buena herramienta XSD que los haga cumplir para él / ella, entonces el valor de XSD se ve disminuido
    • Los validadores JSON están bien, pero no hacen nada para ayudarlo a formar el JSON en primer lugar, y no se llaman automáticamente. No hay garantía de que alguien le envíe un mensaje JSON y lo haya ejecutado a través de un validador. Debes recordar validarlo tú mismo.
    • Las herramientas ASN.1 parecen implementar la comprobación de restricciones.

Entonces para mí, ASN.1 lo hace. Es el menos probable que resulte en que alguien más cometa un error, porque es el que tiene las características correctas y las herramientas aparentemente intentan implementar completamente esas características, y es lo suficientemente neutral para la mayoría de los propósitos.

Para ser honesto, si GPB agregó un mecanismo de restricciones que sería el ganador. XSD está cerca pero las herramientas son casi universalmente basura. Si hubiera generadores de código decentes de otros idiomas, el esquema JSON sería bastante bueno.

Si GPB tenía restricciones añadidas (nota: esto no cambiaría ninguno de los formatos de conexión), sería el que recomendaría a todos para casi cualquier propósito. Aunque el UPER de ASN.1 es muy útil para los enlaces de radio.


boost.serialization solo necesita el compilador de C ++ y le da un poco de sintaxis similar al azúcar

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

para guardar y cargar Si C ++ es el único idioma que utiliza, debe darle a boost.serialization una oportunidad importante.

Eché un vistazo rápido a los búferes de protocolo de Google. Por lo que veo, diría que no es directamente comparable a boost.serialization. Debe agregar un compilador para los archivos .proto a su cadena de herramientas y mantener los archivos .proto. La API no se integra en C ++ como lo hace boost.serialization.

boost.serialization hace muy bien el trabajo: serializar objetos C ++ :) OTOH una consulta API como búferes de protocolo de Google le da más flexibilidad.

Como solo usé boost.serialization hasta ahora, no puedo comentar la comparación de rendimiento.


Boost Serialization

  • es una biblioteca para escribir datos en una secuencia.
  • no comprime datos
  • no admite el control de versiones de datos automáticamente.
  • admite contenedores STL.
  • las propiedades de los datos escritos dependen de las secuencias elegidas (por ej., endian, comprimido).

Buffers de protocolo

  • genera código a partir de la descripción de la interfaz (admite C ++, Python y Java por defecto. C, C # y otros por terceros).
  • opcionalmente comprime datos.
  • maneja el control de versiones de datos automáticamente.
  • maneja el intercambio endian entre plataformas.
  • no admite contenedores STL.

La serialización Boost es una biblioteca para convertir un objeto en una secuencia serializada de datos. Los búferes de protocolo hacen lo mismo, pero también hacen otro trabajo para usted (como el control de versiones y el intercambio de endian). La serialización de Boost es más simple para "pequeñas tareas simples". Los búferes de protocolo son probablemente mejores para una "infraestructura más grande".

EDITAR: 24-11-10: Se agregó "automáticamente" a las versiones de BS.