XML与二进制在序列化/反序列化中的性能比较

9
我正在开发一个紧凑框架应用程序,需要提高性能。该应用程序目前通过将对象序列化为XML并将其存储在数据库中来脱机工作。使用分析工具,我可以看到这是相当大的开销,导致应用程序变慢。我认为如果我切换到二进制序列化,性能会提高,但由于紧凑框架不支持此功能,因此我查看了protobuf-net。序列化似乎更快,但反序列化要慢得多,并且应用程序正在执行更多的反序列化操作。

二进制序列化应该更快,如果是这样的话,我该如何提高性能?以下是我如何同时使用XML和二进制的片段:

XML序列化:

public string Serialize(T obj)
{
  UTF8Encoding encoding = new UTF8Encoding();
  XmlSerializer serializer = new XmlSerializer(typeof(T));
  MemoryStream stream = new MemoryStream();
  XmlTextWriter writer = new XmlTextWriter(stream, Encoding.UTF8);
  serializer.Serialize(stream, obj);
  stream = (MemoryStream)writer.BaseStream;
  return encoding.GetString(stream.ToArray(), 0, Convert.ToInt32(stream.Length));
}
public T Deserialize(string xml)
{
  UTF8Encoding encoding = new UTF8Encoding();
  XmlSerializer serializer = new XmlSerializer(typeof(T));
  MemoryStream stream = new MemoryStream(encoding.GetBytes(xml));            
  return (T)serializer.Deserialize(stream);
}

Protobuf-net 二进制序列化:

public byte[] Serialize(T obj)
{
  byte[] raw;
  using (MemoryStream memoryStream = new MemoryStream())
  {
    Serializer.Serialize(memoryStream, obj);
    raw = memoryStream.ToArray();
  }

  return raw;            
}

public T Deserialize(byte[] serializedType)
{
  T obj;
  using (MemoryStream memoryStream = new MemoryStream(serializedType))
  {
    obj = Serializer.Deserialize<T>(memoryStream);
  }
  return obj;
}

我本来想建议使用Red-Gate ANTS性能分析器,但它不支持Compact框架(在谷歌上搜索"red-gate ants profiler compact")。 - Kane
6个回答

6

我要更正一下,Marc Gravall指出第一次迭代建模的开销很大,因此我进行了一些测试,对XML和二进制的序列化和反序列化进行了1000次迭代的平均值。我首先尝试了Compact Framework DLL的v2版本,然后是v3.5版本。以下是我得到的结果,时间以毫秒为单位:

.NET 2.0
================================ XML ====== Binary ===
Serialization 1st Iteration      3236       5508
Deserialization 1st Iteration    1501       318
Serialization Average            9.826      5.525
Deserialization Average          5.525      0.771

.NET 3.5
================================ XML ====== Binary ===
Serialization 1st Iteration      3307       5598
Deserialization 1st Iteration    1386       200
Serialization Average            10.923     5.605
Deserialization Average          5.605      0.279

3
您的方法中主要的开销是实际生成XmlSerializer类。创建序列化器是一个耗时的过程,您应该只为每个对象类型执行一次。尝试缓存序列化器,看看是否能改善性能。
按照这个建议,我在我的应用程序中看到了很大的性能提升,这使我能够继续使用XML序列化。
希望这有所帮助。

1

有趣的想法:

  • 这是哪个版本的CF;2.0?3.5?特别是,CF 3.5具有Delegate.CreateDelegate,使protobuf-net可以比在CF 2.0中更快地访问属性
  • 您是在注释字段还是属性?同样,在CF中,反射优化受到限制;您可以通过使用属性来获得更好的性能,在字段中,我唯一可用的选项是FieldInfo.SetValue

CF中还有许多其他不存在的东西,因此它必须在某些地方做出妥协。对于过于复杂的模型,还存在CF泛型限制的已知问题。修复正在进行中,但这是一个的变化,并且需要“一段时间”。

关于常规(完整).NET的一些指标,包括XmlSerializer和protobuf-net等各种格式的比较在此处


我正在使用CF2.0,并为需要序列化的对象的属性添加了属性。 - Charlie
有可能尝试在 CF 3.5 中(使用 CF 3.5 二进制文件)来看是否能够修复它? - Marc Gravell
这是在多次迭代中平均吗?我也不确定这些数字是CF2还是CF3.5。 - Marc Gravell
这只是一个测试的结果,但每次都非常相似。这是在3.5上的。 - Charlie
关于信息,第一次迭代需要建立模型的开销 - 后续调用可能会更快...我很好奇它为什么比XmlSerializer慢。我很想把它拆开来看;-( - Marc Gravell
显示剩余3条评论

0

你试过为你的类创建自定义序列化类吗?而不是使用通用的 XmlSerializer(它会在运行时创建一堆类)。有一个工具可以做到这一点(sgen)。你可以在构建过程中运行它,并生成一个可以替代 XmlSerializer 的自定义程序集。

如果你使用的是 Visual Studio,可以在项目属性的“构建”选项卡下找到该选项。


0

在序列化对象或将它们写入数据库时,性能是否会受到影响?由于将它们写入可能会影响某种缓慢的存储,我想这比序列化步骤要耗费更多的性能。

请记住,Marc Gravell发布的性能测量是在100万次迭代中进行的。

您正在存储哪种类型的数据库?对象是在内存中序列化还是直接存储?它们是如何发送到数据库的?对象有多大?当一个对象被更新时,您是将所有对象发送到数据库还是只发送已更改的对象?您是否在内存中缓存任何内容,或者每次重新从存储中读取?


对象被存储在SQLCe数据库中,但我可以清楚地看到序列化和反序列化是性能瓶颈,而不是数据库交互。东西也被缓存在内存中,但需要将东西存储在数据库中,以便在应用程序的会话之间检索。 - Charlie

0

XML 处理速度通常较慢,占用大量空间。已经有许多不同的尝试来解决这个问题,如今最流行的方法似乎是将所有内容都放入 gzip 文件中,就像 Open Packaging Convention 一样。

W3C 已经证明了 gzip 方法不够优秀,他们和各种 其他团体 正在研究更好的二进制序列化方法,以适合快速处理和压缩传输。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接