当前位置: 首页 > 知识库问答 >
问题:

ProtoBuf序列化缺少数据,即使对于简单实体也是如此

狄信然
2023-03-14

[更新#1]:我已经将我修改和修复的“演示”项目上传到https://github.com/sidshetye/SerializersCompare是否还有人有兴趣查看基准。

[更新#2]:我发现ProtoBufs仅在后续迭代中占据数量级领先地位。对于一次性序列化,BinaryFormatter要快一个数量级。为什么?单独的问题。。。

我试图比较BinaryFormatter和Json。NET和ProtoBuf。NET(今天从NuGet上获得了后者)。我发现ProtoBuf没有输出实数字段,都是null和0(见下文)。加上BinaryFormatter似乎要快得多。我基本上序列化了=

  • 带有重新生成对象的原始对象
  • 字节大小
  • ms中的时间

问题

  1. 我怎样才能让ProtoBuf真正说出真正的值,而不仅仅是(默认值?)价值观
  2. 我在速度方面做错了什么?我以为ProtoBuf应该是最快的连载程序

我从测试应用程序获得的输出如下:

Json: Objects identical
Json in UTF-8: 180 bytes, 249.7054 ms

BinaryFormatter: Objects identical
BinaryFormatter: 512 bytes, 1.7864 ms

ProtoBuf: Original and regenerated objects differ !!
====Regenerated Object====
{
    "functionCall": null,
    "parameters": null,
    "name": null,
    "employeeId": 0,
    "raiseRate": 0.0,
    "addressLine1": null,
    "addressLine2": null
}
ProtoBuf: 256 bytes, 117.969 ms

我的测试是在控制台应用程序中使用一个简单实体(见下文)。系统:Windows 8x64,VS2012更新1。NET4.5。顺便说一句,我使用[协议][协议成员(X)]约定得到了相同的结果。文档不清楚,但似乎DataContract是较新的“统一”支持约定(对吗?)

[Serializable]
[DataContract]
class SimpleEntity
{
    [DataMember(Order = 1)]
    public string functionCall {get;set;}

    [DataMember(Order = 2)]
    public string parameters { get; set; }

    [DataMember(Order = 3)]
    public string name { get; set; }

    [DataMember(Order = 4)]
    public int employeeId { get; set; }

    [DataMember(Order = 5)]
    public float raiseRate { get; set; }

    [DataMember(Order = 6)]
    public string addressLine1 { get; set; }

    [DataMember(Order = 7)]
    public string addressLine2 { get; set; }

    public SimpleEntity()
    {
    }

    public void FillDummyData()
    {
        functionCall = "FunctionNameHere";
        parameters = "x=1,y=2,z=3";

        name = "Mickey Mouse";
        employeeId = 1;
        raiseRate = 1.2F;
        addressLine1 = "1 Disney Street";
        addressLine2 = "Disneyland, CA";
    }
}

对于那些感兴趣的人,这里是我的所有序列化程序类的片段

public byte[] SerProtoBuf(object thisObj)
{
    using (MemoryStream ms = new MemoryStream())
    {
        Serializer.Serialize(ms, thisObj);
        return ms.GetBuffer();
    }
}

public T DeserProtoBuf<T>(byte[] bytes)
{

    using (MemoryStream ms = new MemoryStream())
    {
        ms.Read(bytes, 0, bytes.Count());
        return Serializer.Deserialize<T>(ms);
    }
}

共有1个答案

辛盛
2023-03-14

首先,您的序列化/反序列化方法都损坏了;您过度报告了结果(GetBuffer(),没有Llong),并且您没有将任何内容写入流以进行反序列化。这是一个正确的实现(尽管如果您返回ArraySegment,您也可以使用GetBuffer()

public static byte[] SerProtoBuf(object thisObj)
{
    using (MemoryStream ms = new MemoryStream())
    {
        Serializer.NonGeneric.Serialize(ms, thisObj);
        return ms.ToArray();
    }
}

public static T DeserProtoBuf<T>(byte[] bytes)
{
    using (MemoryStream ms = new MemoryStream(bytes))
    {
        return Serializer.Deserialize<T>(ms);
    }
}

这就是为什么您没有得到任何数据。其次,您没有说明如何对其进行计时,所以这里有一些我根据您的代码编写的代码(其中还包括显示它正在获取所有值的代码)。结果优先:

Via BinaryFormatter:
1 Disney Street
Disneyland, CA
1
FunctionNameHere
Mickey Mouse
x=1,y=2,z=3
1.2

Via protobuf-net:
1 Disney Street
Disneyland, CA
1
FunctionNameHere
Mickey Mouse
x=1,y=2,z=3
1.2

Serialize BinaryFormatter: 112 ms, 434 bytes
Deserialize BinaryFormatter: 113 ms
Serialize protobuf-net: 14 ms, 85 bytes
Deserialize protobuf-net: 19 ms

分析:

两个序列化程序存储相同的数据;protobuf网的速度快了一个数量级,产量也小了5倍。我宣布:胜利者。

代码:

static BinaryFormatter bf = new BinaryFormatter();
public static byte[] SerBinaryFormatter(object thisObj)
{
    using (MemoryStream ms = new MemoryStream())
    {
        bf.Serialize(ms, thisObj);
        return ms.ToArray();
    }
}

public static T DeserBinaryFormatter<T>(byte[] bytes)
{
    using (MemoryStream ms = new MemoryStream(bytes))
    {
        return (T)bf.Deserialize(ms);
    }
}
static void Main()
{
    SimpleEntity obj = new SimpleEntity(), clone;
    obj.FillDummyData();

    // test that we get non-zero bytes
    var data = SerBinaryFormatter(obj);
    clone = DeserBinaryFormatter<SimpleEntity>(data);
    Console.WriteLine("Via BinaryFormatter:");
    Console.WriteLine(clone.addressLine1);
    Console.WriteLine(clone.addressLine2);
    Console.WriteLine(clone.employeeId);
    Console.WriteLine(clone.functionCall);
    Console.WriteLine(clone.name);
    Console.WriteLine(clone.parameters);
    Console.WriteLine(clone.raiseRate);
    Console.WriteLine();

    data = SerProtoBuf(obj);
    clone = DeserProtoBuf<SimpleEntity>(data);
    Console.WriteLine("Via protobuf-net:");
    Console.WriteLine(clone.addressLine1);
    Console.WriteLine(clone.addressLine2);
    Console.WriteLine(clone.employeeId);
    Console.WriteLine(clone.functionCall);
    Console.WriteLine(clone.name);
    Console.WriteLine(clone.parameters);
    Console.WriteLine(clone.raiseRate);
    Console.WriteLine();

    Stopwatch watch = new Stopwatch();
    const int LOOP = 10000;

    watch.Reset();
    watch.Start();
    for (int i = 0; i < LOOP; i++)
    {
        data = SerBinaryFormatter(obj);
    }
    watch.Stop();
    Console.WriteLine("Serialize BinaryFormatter: {0} ms, {1} bytes", watch.ElapsedMilliseconds, data.Length);

    watch.Reset();
    watch.Start();
    for (int i = 0; i < LOOP; i++)
    {
        clone = DeserBinaryFormatter<SimpleEntity>(data);
    }
    watch.Stop();
    Console.WriteLine("Deserialize BinaryFormatter: {0} ms", watch.ElapsedMilliseconds, data.Length);

    watch.Reset();
    watch.Start();
    for (int i = 0; i < LOOP; i++)
    {
        data = SerProtoBuf(obj);
    }
    watch.Stop();
    Console.WriteLine("Serialize protobuf-net: {0} ms, {1} bytes", watch.ElapsedMilliseconds, data.Length);

    watch.Reset();
    watch.Start();
    for (int i = 0; i < LOOP; i++)
    {
        clone = DeserProtoBuf<SimpleEntity>(data);
    }
    watch.Stop();
    Console.WriteLine("Deserialize protobuf-net: {0} ms", watch.ElapsedMilliseconds, data.Length);
}

最后,<代码>[数据成员(…)] 支持并不是真正的“较新的‘统一’支持约定”-它当然不是“较新的”-我很确定它在类似提交4(可能更早)的时候就已经支持了这两种约定。这只是为了方便起见提供的选项:

  • 并非所有目标平台都具有DataMemberAttribute
  • 有些人喜欢将DTO层限制为内置标记
  • 有些类型基本上不受您的控制,但可能已经有了这些标记(例如,从LINQ到SQL生成的数据)
  • 此外,请注意2。x允许您在运行时定义模型,而无需添加属性(尽管属性仍然是最方便的方式)

 类似资料:
  • 我需要通过flink消费Kafka,不幸的是,Kafka消息是在serde中使用原型,完全不知道如何处理它,这里是来自互联网的代码,但我不能使它工作。 这不起作用,它会让NPE: 有人知道我做错了什么吗?使用twitter ProtobufSerializer是唯一值得拥有protobuf的方法吗?还是还有别的路要走?

  • 问题内容: 我可能只是弄乱了原始文件中的内容,但似乎无法调用toByteArray函数。 使用Java,proto文件是使用protoc编译的。 我在说… 并且BaseMessage被声明为… 也许我缺少东西… BaseMessage扩展了GeneratedMessage,它继承了其中toByteArray是公共的AbstractMessageLite的 toByteArray(),所以我应该能够

  • 问题内容: 我正在尝试将.NET DataTable序列化为JSON文件,然后将JSON文件反序列化为DataTable。我想很简单。 但是,我有一个表,3行3列,每个元素的类型都是double。如果第一行中的任何值为null,则当JSON.Net将json文件反序列化为DataTable对象时,第一行中为null的列的所有值都变为字符串。 需要明确的是,只有第一行的值为空时,才会发生这种情况。如

  • 本文向大家介绍jQuery序列化表单成对象的简单实现,包括了jQuery序列化表单成对象的简单实现的使用技巧和注意事项,需要的朋友参考一下 在使用easyui的datagrid组件时,在查询时传递的查询参数是对象类型,为了方便,扩展了jquery中的序列化方法,调用该方法,可以将表单的所有数据序列化 具体使用: 以上这篇jQuery序列化表单成对象的简单实现就是小编分享给大家的全部内容了,希望能给

  • 问题内容: 我正在尝试使用protobuf序列化结构。经过许多小时试图弄清楚我在做什么错,我决定测试google的示例,但效果不佳 我从Google(https://developers.google.com/protocol- buffers/docs/javatutorial )获得以下协议: 我正在尝试将其序列化: byte []序列化= john.toByteArray(); 我得到“ j

  • 试图在Java中使用protobuf反序列化消息,并得到以下异常。 原因:com.google.protobuf.InvalidProtocolBufferException:在解析协议消息时,输入意外地在字段中间结束。这可能意味着输入被截断,或者嵌入的消息错误报告了自己的长度。在com.google.protobuf.InvalidProtocolBufferException.Truncate