protoBuf比BinaryFormatter更慢,更大

时间:2014-03-12 03:56:00

标签: .net serialization protobuf-net

在一个简单的测试中,当主数据为Dictionary<int, string>时,protoBuf v2比BinaryFormatter慢得多。 protoBuf时间为931ms,流大小为7,950,000。 BinaryFormatter时间为52毫秒,流大小为193,798。所以这是一个很大的不同。

这是完整的测试代码:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using ProtoBuf;

namespace SerDeser
{
    class Program
    {
        static void Main(string[] args)
        {
            const int HOW_MANY = 10000;
            var data = new TestClass[HOW_MANY];
            var d1 = new Dictionary<int, string>();
             for (var i = 1; i <= 100; i++)
            {
                d1.Add(i, i.ToString());
            }
            for (var i = 0; i < HOW_MANY; i++)
            {
                data[i] = new TestClass() {InnerData = d1};
            }
            SerDeser(data, "BinaryFormatter", false);
            SerDeser(data, "ProtoBuf", true);
            Console.ReadLine();
        }

        private static void SerDeser(TestClass[] data, string label, bool useProtoBuf)
        {
            var timer = new Stopwatch();
            IFormatter formatter = null;
            using (var ms = new MemoryStream())
            {
                timer.Start();
                if (useProtoBuf)
                {
                    Serializer.Serialize<TestClass[]>(ms, data);
                }
                else
                {
                    formatter = new BinaryFormatter();
                    formatter.Serialize(ms, data);
                }
                TestClass[] clone = null;
                var serTime = timer.ElapsedMilliseconds;
                timer.Reset();
                timer.Start();
                ms.Position = 0;
                if (useProtoBuf)
                {
                    clone = Serializer.Deserialize<TestClass[]>(ms);
                }
                else
                {
                    clone = formatter.Deserialize(ms) as TestClass[];
                }
                timer.Stop();
                Console.WriteLine(string.Format("{0}: ser {1}ms; deser {2}ms; total {3}ms; length {4}", label, serTime, timer.ElapsedMilliseconds, serTime + timer.ElapsedMilliseconds, ms.Length));
                if (clone.Length != data.Length) Console.WriteLine("length error.");
                if (clone[1].InnerData.Count != data[1].InnerData.Count) Console.WriteLine("Content error 1");
                if (clone[1].InnerData[1] != data[1].InnerData[1]) Console.WriteLine("Content error 2");
            }
        }

    }

    [ProtoContract]
    [Serializable]
    public class TestClass
    {
        public TestClass()
        {
        }
        [ProtoMemberAttribute(1)] public Dictionary<int, string> InnerData;

    }

}

我创建了一个包含10,000个数组的数组,每个数组的InnerData属性都是一个包含100个条目的字典。我的测试序列化和反序列化数组。

对于protobuf测试,我只使用Serializer.Serialize(ms),其中ms是一个MemoryStream。 (和Serializer.DeSerialize反序列化)。如果被问到,我可以发布测试驱动程序代码。

所以我的问题是,在什么条件下我应该期望protoBuf比BinaryFormatter更慢或更快?

1 个答案:

答案 0 :(得分:2)

这是因为您每次都重复完全相同的InnerData实例。 BinaryFormatter始终跟踪引用。 protobuf-net 可以跟踪引用,但默认情况下不会这样做,因为google规范没有这个概念。

但是,我怀疑多次序列化同一个实例是一个有用的测试 - 它很少代表任何一个序列化器的实际用法。

要进行实际测试,请为每个InnerData生成不同的HOW_MANY个实例,并确保string每次都是不同的字符串实例(同样,BinaryFormatter将跟踪string上的引用。

或者,在protobuf-net中启用参考跟踪。不幸的是,对于string的直接子项Dictionary<int,string>,您无法轻松执行此操作。

这是我的改变:

static void Main(string[] args)
{
    const int HOW_MANY = 10000;
    var data = new TestClass[HOW_MANY];
    for (var i = 0; i < HOW_MANY; i++)
    {
        Dictionary<int, string> d1 = InventData();
        data[i] = new TestClass() { InnerData = d1 };
    }
    SerDeser(data, "BinaryFormatter", false);
    SerDeser(data, "ProtoBuf", true);
    Console.ReadLine();
}

private static Dictionary<int, string> InventData()
{
    var d1 = new Dictionary<int, string>();
    for (var i = 1; i <= 100; i++)
    {
        d1.Add(i, i.ToString());
    }

    return d1;
}

结果(我添加了千位分隔符以便于比较):

BinaryFormatter: ser 3,413ms; deser 30,833ms; total 34,246ms; length 23,821,447
ProtoBuf: ser 450ms; deser 591ms; total 1,041ms; length 7,950,000

我知道我更喜欢哪个!