Bibliotecas de serialización en C++

Abdul Mateen 11 diciembre 2023
  1. Descripción general de la serialización
  2. Bibliotecas de serialización en C++
  3. Comparación entre todas las bibliotecas de serialización
Bibliotecas de serialización en C++

En este tutorial, aprenderá sobre las diferentes bibliotecas de serialización de C++.

Primero, aprenderemos sobre la serialización y su propósito en C++. A continuación, analizaremos las bibliotecas de serialización en C++ y cómo usarlas en nuestro programa.

Descripción general de la serialización

Los programadores trabajan rutinariamente con objetos de datos en la memoria. Y a veces, los objetos deben enviarse a través de una red o escribirse en un almacenamiento persistente (normalmente un archivo) para guardar algunas partes del estado del programa.

La serialización es el proceso/técnica de transformar los datos o el estado del objeto en un formato binario. La forma binaria es el flujo de bytes para almacenar/preservar el estado del objeto o transmitirlo a la memoria, base de datos, archivo o disco a través de una red informática.

El reverso del proceso de serialización se conoce como deserialización. La serialización es ideal cuando desea mantener el estado de los datos estructurados (es decir, clases o estructuras de C++) durante o después de la ejecución del programa.

Puede leer sobre serialize() y deserialize() con un ejemplo en este sitio web.

La serialización proporciona una representación de bytes estable del valor de los objetos de software. Luego, estos bytes se pueden enviar a través de una red que seguirá funcionando correctamente incluso en implementaciones futuras que utilicen hardware y software diferentes.

Serialización en Varios Idiomas

Antes de seguir adelante, el proceso de serialización se implementa de manera diferente en diferentes idiomas. Vamos a explorarlos a continuación.

  1. En Java, el método de serialización es writeObject, que se implementa en ObjectOutputStream.
  2. En Python, el método de serialización es un pickle.dumps().
  3. En Ruby, el método de serialización es marshal.dump().
  4. En C++, el método es boost::archive::text_oarchive a (nombre de archivo); a << datos; invocar el método de serialización
  5. En MFC (Microsoft Foundation Class Library), el método de serialización es: conducir su clase desde CObject.

Nuestro enfoque principal es la serialización de C++, así que veamos cómo funciona.

C++ Boost.Serialization utiliza objetos de archivo de texto. La serialización escribe en un objeto de archivo de salida que funciona como un flujo de datos de salida.

Cuando se invoca para tipos de datos de clase, el operador de salida >> llama a la clase para serializar la función. Cada función de serialización utiliza el operador &, o mediante >>, serializa recursivamente objetos anidados para guardar o cargar sus miembros de datos.

Para comprender mejor la serialización en C++, puede consultar este sitio web.

Bibliotecas de serialización en C++

C++ proporciona muchas bibliotecas para la serialización excepto para la serialización de Boost. Todas las bibliotecas ayudan a lograr un alto rendimiento de serialización, así que exploremos algunas.

Protobuf

Protocol Buffers (Protobufs), una plataforma cruzada utilizada para serializar los datos. Es útil para la comunicación entre los programas a través de una red.

El mecanismo de serialización de Protobuf se da a través de la aplicación de protocolo. Este compilador analizará el archivo .proto y generará, como salida, archivos fuente según el lenguaje configurado por sus argumentos, en este caso, C++.

Puedes leer el tutorial en este enlace para entender mejor Protobufs.

FlatBuffers

FlatBuffers es una plataforma cruzada de código abierto que se utiliza para lograr la máxima eficiencia de la memoria. Puede acceder directamente a los datos serializados sin analizarlos con compatibilidad hacia adelante/hacia atrás.

Usando FlatBuffers, primero genera su esquema C++ con la opción --CPP. Luego puede incluir Flatbuffer en el archivo para leer o escribir este código generado.

Puede encontrar la implementación de serialización utilizando FlatBuffers en este enlace.

Cereal

Cereal es la biblioteca de serialización C++ 11 de solo encabezado. Cereal toma tipos de datos arbitrarios y los convierte de forma reversible en diferentes representaciones, como codificaciones binarias compactas, XML o JSON.

Cereal es extensible, rápido, probado por unidad y ofrece una sintaxis familiar como Boost. Para descargar la biblioteca completa de cereales, haga clic aquí.

A continuación, tenemos un ejemplo que muestra el uso de la biblioteca de cereales:

#include <cereal/archives/binary.hpp>
#include <cereal/types/memory.hpp>
#include <cereal/types/unordered_map.hpp>
#include <fstream>

struct MyRecord {
  uint8_t x, y;
  float z;
  template <class Archive>
  void serialize(Archive& ar) {
    ar(x, y, z);
  }
};
struct SomeData {
  int32_t id;
  std::shared_ptr<std::unordered_map<uint32_t, MyRecord>> data;
  template <class Archive>
  void save(Archive& ar) const {
    ar(data);
  }
  template <class Archive>
  void load(Archive& ar) {
    static int32_t idGen = 0;
    id = idGen++;
    ar(data);
  }
};
int main() {
  std::ofstream out("out.cereal", std::ios::binary);
  cereal::BinaryOutputArchive archive(out);
  SomeData myData;
  archive(myData);
  return 0;
}

En la función principal, creamos un nombre de archivo binario os.cereal en modo binario.

En la siguiente línea, creamos un objeto de la clase BinaryOutputArchive a partir de binary.hpp definido en la carpeta de archivos de la biblioteca de cereales. Estamos pasando nuestro objeto de archivo al constructor de BinaryOutputArchive.

A continuación, creamos nuestro objeto de datos para serializar, el objeto de clase algunos datos. Finalmente, en la cuarta línea de la función principal, pasamos nuestro objeto de datos al archivo, llamando indirectamente a la función guardar para guardar datos en el archivo de salida para guardar un objeto serializado en el archivo de salida out.cereal.

El archivo binario, out.cereal tiene nuestros datos serializados. La salida de este código serán datos en el archivo out.cereal.

Estos datos están en forma binaria y podemos verificarlos usando diferentes utilidades/comandos disponibles en diferentes sistemas operativos.

HPS

HPS es una herramienta de simulación de alto rendimiento y es la biblioteca de solo encabezado para la serialización de datos en C++11. HPS codifica sus datos en un formato comprimido para pasar fácilmente por la red.

HPS es un 150 % más rápido que la serialización boost normal en C++, ya que solo requiere una línea de código para las bibliotecas de plantillas estándar y los tipos de datos primitivos.

También puede usar las funciones write to_stream y from_stream para leer y escribir datos en los archivos. Para una mejor comprensión de HPS, también puede visitar este sitio web.

Paquete de mensajes de GitHub

MessagePack es un formato de serialización específico de código abierto. Puede intercambiar datos fácilmente en diferentes formatos como JSON y XML.

El valor entero requiere solo un byte para codificar datos, mientras que el valor de cadena requiere un byte adicional.

Para una mayor implementación de msgpack, puede visitar el enlace.

Boost.Serialización

La biblioteca Boost Serialization en C++ hace posible convertir objetos en bytes para guardarlos y cargarlos para restaurarlos. Diferentes formatos generan las secuencias de bytes.

Todos estos formatos son compatibles con Boost. La serialización solo está diseñada para usarse con esta biblioteca.

En C++, cada objeto que va a serializar requiere que implemente el método de serialización. Debe tomar un archivo como argumento; un archivo es similar a un flujo de datos de entrada/salida.

En lugar de usar los operadores << o >>, puede usar el operador general y manejar las operaciones de guardado y carga del bot. Puede leer sobre la serialización de impulso en este sitio web.

apache avro

Apache Avro es un sistema de serialización de datos. Avro C++ es una biblioteca de C++ que implementa las especificaciones de Avro, y la biblioteca está diseñada para usarse en la canalización de transmisión.

Por ejemplo, Apache Kafka realiza la serialización y deserialización de datos con esquemas administrados centralmente.

Avro no requiere generación de código; puede utilizar la herramienta de generación de código. El generador de código lee un esquema y genera un objeto C++ para representar los datos del esquema en .schema.

También crea el código para serializar este objeto y deserializarlo. Aquí, toda la codificación pesada se hace por ti.

Incluso si desea escribir serializadores o analizadores personalizados usando las bibliotecas principales de C++, el código generado puede ser un ejemplo de cómo usar estas bibliotecas.

Este estilo puede funcionar, pero puede hacer que struct o class sean serializables para obtener la solución perfecta.

Capitán Proto

Cap’n Proto puede intercambiar fácilmente el formato de datos, ya que su capacidad depende del sistema RPC (llamada a procedimiento remoto). No existe el concepto de codificación/descodificación en Cap'n Proto.

El formato de intercambio de datos actúa como codificación y representa la memoria. Puede escribir fácilmente bytes directamente desde el disco estructurando sus datos.

Puede encontrar el mejor ejemplo en la página Cap’n Proto.

Ahorro

Apache Thrift es un marco de serialización que se enfoca en problemas de lenguaje. Puede definir tipos de datos abstractos en IDL (Lenguaje de definición de interfaz), que luego se compilará en el código fuente para cualquier idioma compatible.

Luego, estos códigos generados proporcionarán una serialización completa para los tipos definidos por el usuario. Apache Thrift garantiza que cualquier tipo de datos se pueda leer o escribir con él.

Puede encontrar el mejor ejemplo de Apache Thrift en esta página.

YA

YAS se crea como reemplazo de Boost.serialization debido a su baja velocidad de serialización; también es un archivo de solo encabezado y no requiere bibliotecas de terceros. Admite los formatos binario, de prueba y JSON y requiere C++11.

Puede leer sobre YAS en esta página.

Comparación entre todas las bibliotecas de serialización

Todas estas bibliotecas brindan serialización y tienen las suyas en diferentes períodos. Solo le mostramos los resultados de estas bibliotecas, mientras que puede encontrar el código y más detalles en esta página (la misma línea ya se comparte en la línea anterior).

Aquí, en este artículo, mostramos los resultados tomados de un artículo.

Este código se ejecutó en una computadora de escritorio típica con un procesador Intel Core i7 con Ubuntu 16.04 y se calculó su tiempo promedio.

serializador Tamaño del objeto Tiempo medio total
binario de ahorro 17017 1190.22
ahorro-compacto 13378 3474.32
Protobuf 16116 2312.78
aumentar 17470 1195.04
paquete de mensajes 13402 2560.6
cereal 17416 1052.46
Avro 16384 4488.18
17416 302.7
yas-compacto 13321 2063.34

Cap’n Proto y Flatbuffers almacenan datos en forma serializada, donde la serialización significa llevar el puntero al almacenamiento interno. Por lo tanto, en Cap’n Proto, medimos todo el ciclo de compilación/serialización/deserialización.

En el caso de otras bibliotecas, también podemos serializar/deserializar el ciclo de la estructura de datos ya construida.

serializador tamaño del objeto promedio Tiempo Total
capnproto 17768 400.98
búferes planos 17632 491.5

Si ve la representación de datos anterior según el tamaño, YAS toma más tamaño de objeto que otras bibliotecas. Aún así, YAS toma poco tiempo si considera el tiempo de serialización.

Por lo tanto, YAS muestra la serialización más rápida entre todas las bibliotecas.

Nota: El tamaño se mide en bytes y el tiempo se mide en milisegundos.

Esperamos que ahora comprenda la serialización y sus usos. Ahora, sabe qué bibliotecas pueden serializar en C++ o qué biblioteca puede lograr más rápido.