serialization protobuf-net binary-serialization

serialization - ¿Protobuf-net tiene compresión incorporada para la serialización?



binary-serialization (1)

Estaba haciendo algunas comparaciones entre BinaryFormatter y Protobuf-net serializador y estaba bastante satisfecho con lo que found , pero lo extraño fue que Protobuf-net logró serializar los objetos en una matriz de bytes más pequeña que la que obtendría si escribiera el el valor de cada propiedad en una matriz de bytes sin metadatos.

Sé que Protobuf-net admite el internado de cadenas si establece AsReference en true , pero no lo estoy haciendo en este caso, ¿entonces Protobuf-net proporciona alguna compresión por defecto?

Aquí hay algunos códigos que puedes ejecutar para ver por ti mismo:

var simpleObject = new SimpleObject { Id = 10, Name = "Yan", Address = "Planet Earth", Scores = Enumerable.Range(1, 10).ToList() }; using (var memStream = new MemoryStream()) { var binaryWriter = new BinaryWriter(memStream); // 4 bytes for int binaryWriter.Write(simpleObject.Id); // 3 bytes + 1 more for string termination binaryWriter.Write(simpleObject.Name); // 12 bytes + 1 more for string termination binaryWriter.Write(simpleObject.Address); // 40 bytes for 10 ints simpleObject.Scores.ForEach(binaryWriter.Write); // 61 bytes, which is what I expect Console.WriteLine("BinaryWriter wrote [{0}] bytes", memStream.ToArray().Count()); } using (var memStream = new MemoryStream()) { ProtoBuf.Serializer.Serialize(memStream, simpleObject); // 41 bytes! Console.WriteLine("Protobuf serialize wrote [{0}] bytes", memStream.ToArray().Count()); }

EDIT: se olvidó de agregar, la clase SimpleObject se parece a esto:

[Serializable] [DataContract] public class SimpleObject { [DataMember(Order = 1)] public int Id { get; set; } [DataMember(Order = 2)] public string Name { get; set; } [DataMember(Order = 3)] public string Address { get; set; } [DataMember(Order = 4)] public List<int> Scores { get; set; } }


No, no lo hace; no hay "compresión" como tal especificada en la especificación de protobuf; sin embargo, (de manera predeterminada) usa "codificación varint" - una codificación de longitud variable para datos enteros que significa que los valores pequeños usan menos espacio; así 0-127 toma 1 byte más el encabezado. Tenga en cuenta que el varint por sí solo es bastante descabellado para los números negativos, por lo que la codificación "zigzag" también es compatible, lo que permite que los números de pequeña magnitud sean pequeños (básicamente, intercala pares positivos y negativos).

En realidad, en su caso para los Scores , también debería ver la codificación "empaquetada", que requiere [ProtoMember(4, IsPacked = true)] o el equivalente a través de TypeModel en v2 (v2 admite cualquiera de los dos enfoques). Esto evita la sobrecarga de un encabezado por valor, al escribir un solo encabezado y la longitud combinada . "Empaquetado" se puede usar con varint / zigzag. También hay codificaciones de longitud fija para escenarios en los que sabe que los valores son probablemente grandes e impredecibles.

Tenga en cuenta también: pero si sus datos tienen una gran cantidad de texto, puede beneficiarse de ejecutarlos a través de gzip o deflate; si no lo hace , entonces tanto gzip como deflate podrían hacer que se agrande.

Una visión general del formato de cable está aquí ; no es muy difícil de entender y puede ayudarlo a planificar la mejor manera de optimizar.