在一个简单的测试中,当主数据为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更慢或更快?
答案 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
我知道我更喜欢哪个!