提高 XmlSerializer 性能

9
我使用XmlSerializer来序列化/反序列化一些对象,但性能不佳。在分析时,使用XmlSerializer会导致应用程序启动时间延长2秒钟。我们缓存了XmlSerializer并重复使用它们。由于我们正在使用XmlAttributeOverrides创建XmlSerializer,所以不能使用sgen.exe。
我尝试使用类似Json.Net的序列化替代方案,最开始运行良好。但问题是,我们需要向后兼容,因此所有已生成的xml都需要正确解析。此外,对象序列化输出必须是Xml格式。
简而言之:
1. 我收到由XmlSerializer序列化的Xml数据。 2. 我需要反序列化Xml数据并将其转换为对象。 3. 我需要将对象序列化为Xml(理想情况下是像XmlSerializer所做的那样的Xml格式)。

我更新了我的问题,以更准确地代表我的问题。 - Melursus
1
这只是XmlSerializer的启动时间问题吗?就像Oleg所说,如果使用得当(例如调用良好的构造函数等),序列化/反序列化时间可以非常快(它已经编译)。 - Simon Mourier
是的,这只发生在启动时,因为我们在启动时反序列化对象。花费时间的是构建XmlSerializer。之后,速度非常快,但我们需要改善启动时间。 - Melursus
你也可以同时使用json和xml。如果json文件存在,则加载它,否则加载xml文件。当需要更新时,当然要保存xml和json两个文件。 - L.B
@MarcGravell:谢谢!那是打字错误。我是说,当然是 IXmlSerializable - Oleg
显示剩余4条评论
7个回答

13

最终,这取决于您的模型复杂程度。 XmlSerializer 需要进行大量思考,而它花费如此之长的时间让我怀疑您的模型相当复杂。对于一个简单的模型,也许可以使用 LINQ-to-XML(非常容易)或者甚至 XmlReader(如果您感到非常勇敢——要实现100%的正确性并不容易)手动实现反序列化。

然而,如果模型很复杂,这是一个问题,而且可能会出现引入微妙错误的风险。

另一个选择是 DataContractSerializer,它处理 xml,但没有 XmlSerializer 做得好,并且肯定不能像后者一样对布局有更多的控制。我强烈怀疑 DataContractSerializer 对您没有帮助。

我不知道是否有直接替代 XmlSerializer 的方法,如果 sgen.exe 不是一个选项,我认为您基本上有以下几种选择:

  • 忍受这种情况
  • 自己重写 XmlSerializer,以某种方式做得比他们更好
  • 使用类似于 LINQ-to-XML 的东西并接受其中所涉及的工作量

从长远来看,我建议“切换格式”,只使用 xml 进行旧数据的导入。我碰巧知道一些非常快的二进制协议,可以很容易地替代它 ;p


非常出色的回答。在一个项目中,我必须使用接口而不是抽象类(因为C#不支持多重继承),做了类似的事情。使用LINQ to XML和反射搞定了这个问题。我的下一个任务是用属性代替参数中的规则列表(刚学会这个)。我必须说这很有趣。 - pqsk

2

这篇回答中提供了一些关于为什么XmlAttributeOverrides会导致XmlSerializer运行缓慢的好信息。

你真的需要在启动主线程时使用XmlSerializer吗?

也许可以在后台线程中运行它;如果只有部分数据是启动过程中必须的,也许你可以手动将它们读入代理/稀疏版本的真实类,同时XmlSerializer进行初始化。

如果它是一个GUI应用程序,你可以添加一个启动画面来隐藏延迟(或者玩俄罗斯方块!!)

如果所有其他方法都失败了,难道不能通过运行现有的反序列化和JSON序列化来将现有文件转换为JSON吗?或者有一个必须保持它们为XML的硬要求吗?


2
问题在于您请求的类型并未被 sgen 覆盖,这会导致在启动过程中生成新的程序集。
您可以尝试获取 Xmlserializer 为特定类型生成的临时文件,并使用此代码生成您自己的预生成 xmlserializer 程序集。我使用了这种方法来找出为什么执行 csc.exe 延迟了我的应用程序启动。此外,重命名一些类型可能有所帮助,就像文章中那样,以达到与 sgen 创建的相同类型名称,以便使用 sgen。通常情况下,sgen 不会预先创建类型数组,有时这是一个缺点。但是,如果您将您的类命名为 ArrayOfHereGoesYourTypeName,则可以使用预生成的程序集。

1

在此未提及的另一种选项是编译序列化程序集。这样,在 Visual Studio 的编译期间,所有代码生成和代码编译步骤都会发生,而不是在应用程序启动时运行时进行。

OP 提到应用程序启动太慢了。那么,这正是序列化程序集的用途。

在 .NET Core 中,步骤非常简单:

  1. 将 nuget 引用添加到 Microsoft.XmlSerializer.Generator
  2. ...就这样 :)

更多信息请参见 https://learn.microsoft.com/en-us/dotnet/core/additional-tools/xml-serializer-generator

P.S. 如果您仍在使用 .NET Framework(而不是 .NET Core),请参见此问题 Generating an Xml Serialization assembly as part of my build


0

你需要使用经典的 .net Serialization 反序列化你的列表。

类似以下代码:

TextReader tr = new StreamReader("yourlist.xml"); 
XmlSerializer serializer = new XmlSerializer(typeof(List<YourObject>));
List<YourObject> myCutomList = (List<YourObject>)serializer.Deserialize(tr); 
tr.Close(); 

你可以使用Json.Serialization

JavaScriptSerializer json = new JavaScriptSerializer();
JsonResult output = json.Serialize(myCutomList );

我不能使用 .net XmlSerializer,因为在我们的项目中它性能较差。这就是为什么我尝试使用JsonSerializer,但我需要与我们旧的格式兼容,所以我需要处理由XmlSerializer序列化的Xml,而不使用XmlSerializer... - Melursus

0
如果您的XML以无法使用的格式存储,则可以使用XSLT将其转换为可用的格式。
如果此XML以XmlSerializer格式存储 - 比如在平面文件或数据库中 - 则可以运行一次转换,而不会在通常的运行时产生XmlSerializer开销。
或者,您可以在运行时进行XSLT转换 - 但我怀疑这种方法是否比Massimiliano概述的方法更快。

0

您可以使用线程或任务来加快应用程序的启动速度,不必等待硬盘或反序列化。


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