我发现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}");
}
答案 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发生 - 为此,你需要调用一次代码。