奇怪的Protobuf加速通过序列化对象列表

时间:2017-04-04 14:03:13

标签: c# .net list serialization protobuf-net

我发现ProtoBuf在大量复杂对象序列化方面的表现非常奇怪。让我们有这两种情况:

A)逐个序列化对象列表

B)整个列表序列化

凭直觉,这应该有类似的表现。但是,在我的应用程序中,仅通过将对象放在列表中并序列化列表,反序列化就有10倍的差异。 Bellow你可以找到代码来测试这个。在这个例子中,结果在2x和5x加速之间有所不同,但是在我的代码中它的prretty一致10倍加速。

造成这种情况的原因是什么?我有一个应用程序,我需要逐个序列化对象及其真正的降级性能,有没有办法提高逐个序列化的性能< / b>?

由于

代码输出

One by one serialization = 329204 ; deserialization = 41342
List serialization       = 19531 ; deserialization = 27716

代码

[ProtoContract]
    class TestObject
    {
        [ProtoMember(1)]public string str1;
        [ProtoMember(2)]public string str2;
        [ProtoMember(3)]public int i1;
        [ProtoMember(4)]public int i2;
        [ProtoMember(5)]public double d1;
        [ProtoMember(6)]public double d2;
        public TestObject(int cnt)
        {
            str1 = $"Hello World {cnt}";
            str2 = $"Lorem ipsum {cnt}";
            for (int i = 0; i < 2 ; i++) str1 = str1 + str1;
            d1 = i1 = cnt;
            d2 = i2 = cnt * 2;
        }
        public TestObject() { }
    }
    private void ProtoBufTest()
    {
        //init test data
        List<TestObject> objects = new List<TestObject>();
        int numObjects = 1000;
        for(int i = 0; i < numObjects;i++)
        {
            objects.Add(new TestObject(i));
        }
        Stopwatch sw = new Stopwatch();
        MemoryStream memStream = new MemoryStream();

        //test 1 
        sw.Restart();
        for (int i = 0; i < numObjects; i++)
        {
            ProtoBuf.Serializer.SerializeWithLengthPrefix<TestObject>(memStream, objects[i], ProtoBuf.PrefixStyle.Base128);
        }
        long timeToSerializeSeparately = sw.ElapsedTicks;
        memStream.Position = 0;

        sw.Restart();
        for (int i = 0; i < numObjects; i++)
        {
            ProtoBuf.Serializer.DeserializeWithLengthPrefix<TestObject>(memStream, ProtoBuf.PrefixStyle.Base128);
        }
        long timeToDeserializeSeparately = sw.ElapsedTicks;

        //test 2
        memStream.Position = 0;
        sw.Restart();
        ProtoBuf.Serializer.SerializeWithLengthPrefix<List<TestObject>>(memStream, objects, ProtoBuf.PrefixStyle.Base128);
        long timeToSerializeList = sw.ElapsedTicks;

        memStream.Position = 0;
        sw.Restart();
        ProtoBuf.Serializer.DeserializeWithLengthPrefix<List<TestObject>>(memStream,  ProtoBuf.PrefixStyle.Base128);
        long timeToDeserializeList = sw.ElapsedTicks;

        Console.WriteLine($"One by one serialization = {timeToSerializeSeparately} ; deserialization = {timeToDeserializeSeparately}");
        Console.WriteLine($"List serialization       = {timeToSerializeList} ; deserialization = {timeToDeserializeList}");
    }

1 个答案:

答案 0 :(得分:1)

我认为你歪曲了初步的反思预处理和JIT成本;如果我们改变它,那么它会多次运行测试:

static void Main()
{
    ProtoBufTest(1);
    for (int i = 0; i < 10; i++)
    {
        ProtoBufTest(1000);
    }
}

private static void ProtoBufTest(int numObjects)
{
    ...

然后是我期望的结果,单个目标代码更快

基本上,它在第一次需要时会完成很多工作,基本上就是你在这里要求的:

  

是否有某种方法可以强制ProtoBuf在调用之间缓存反射数据?这可能有很大帮助

已经发生了。作为附注,你也可以这样做:

    Serializer.PrepareSerializer<TestObject>();

一旦你的应用程序开始,它会尽可能多地做。我不能强制JIT发生 - 为此,你需要调用一次代码。