30

我在和 protobuf-net 序列化程序之间进行了一些比较,并对我的发现BinaryFormatter感到非常满意,但奇怪的是 protobuf-net 设法将对象序列化为一个比我只写值时得到的更小的字节数组将每个属性转换为没有任何元数据的字节数组。

我知道如果你设置AsReference为protobuf-net 支持字符串实习true,但在这种情况下我没有这样做,那么 protobuf-net 默认提供一些压缩吗?

以下是一些您可以运行自己查看的代码:

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());
}

编辑:忘记添加,SimpleObject该类如下所示:

[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; }
}
4

2 回答 2

38

不,不是的; protobuf 规范中没有指定“压缩”;但是,它确实(默认情况下)使用“varint encoding” - 整数数据的可变长度编码,这意味着小值使用更少的空间;所以 0-127 需要 1 个字节加上标题。请注意, varint本身对于负数来说非常循环,因此还支持“之字形”编码,它允许小幅度数字很小(基本上,它交错正负对)。

实际上,在您的情况下,Scores您还应该查看“打包”编码,这需要 v2 中的任何一个[ProtoMember(4, IsPacked = true)]或等效的 via TypeModel(v2 支持任何一种方法)。这通过编写单个标头和组合长度来避免每个值的标头开销。“打包”可以与 varint/zigzag 一起使用。对于您知道值可能很大且不可预测的情况,还有固定长度的编码。

另请注意:但如果您的数据有很多文本,您可能会受益于通过 gzip 或 deflate 额外运行它;如果没有,那么 gzip 和 deflate 都可能导致它变大。

有线格式的概述在这里;它不是很难理解,并且可以帮助您计划如何最好地进一步优化。

于 2011-08-24T20:32:42.563 回答
0

至少 c++ 库确实支持写入和从压缩流中写入:

https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/io/gzip_stream.h

我不确定是否已将其移植到 .Net 实现中。

于 2020-09-12T00:12:35.730 回答