【问题标题】:XmlSerializer - the first deserialization is very slowXmlSerializer - 第一次反序列化很慢
【发布时间】:2018-02-02 21:35:29
【问题描述】:

我有两个项目的解决方案;一个 asp.net MVC 应用程序和一个类库。我们称它们为 MVC 项目和 CLS 项目。

在 CLS 项目中,有两个不同版本的 XSD 文件(V1 和 V2),我使用 xsd2code 创建了两个同名但在不同命名空间(V1 和 V2)下的可序列化类。

在MVC项目中,当用户上传一个XML文件时,CLS.dll用于将XML反序列化为一个对象。当XML文件是V1类型时,反序列化非常快,但是V2版本的XSD文件要复杂很多,反序列化可能需要几分钟,只有第一次(之后非常快) ,直到应用程序再次运行)。

我使用Sgen.exe 工具为 CLS.V2 类型创建了一个序列化程序程序集 (CLS.XmlSerializers.dll),以消除第一次即时创建程序集,从而提高性能。

我已经成功地将 Sgen 任务添加到 Post Build 事件中,并且每次构建项目时都会创建程序集 CLS.XmlSerializers.dll。此外,我使用了this post 中的单元测试代码来确保程序集已加载,并且确实如此。测试成功通过。

然而,第一次反序列化 XML 文件仍然需要很长时间。所以,还是应该有问题。但是,我不知道是什么。请帮忙。

更新:

我按照 cmets 中的建议使用了 Fuslogvw.exe,我可以看到 CLS.XmlSerializers.dll 正在成功加载。那么,为什么第一次反序列化 XML 文件大约需要 1 分钟,但之后每次都不到 1 秒?

更新 2:

两个 XSD 文件之间的区别之一是第二个 (V2) 引用了一个非常大的 XSD 文件,该文件包含一些在主文件中使用的 xs:enumeration 类型的定义。而且,这就是反序列化需要很长时间的原因。由于我需要做的就是将 XML 文件反序列化为对象,并且不需要针对这些枚举验证属性和元素的值,因此我最终删除了对该 XSD 文件的引用,并将所有枚举类型替换为它们的基本类型(在本例中为xs:string)。现在,V2 的反序列化速度和 V1 一样快,我什至不需要使用 Sgen.exe。我猜Sgen.exe 仅在需要反序列化非常大的 XML 文件的情况下才有帮助。在我的例子中,XML 文件总是非常小,但是反序列化是(曾经)复杂的。

【问题讨论】:

  • “它很慢”并不能完全保证。但可以肯定的是,DLL 位于错误的目录中的可能性总是很大。不要猜测,运行 Fuslogvw.exe 并记录所有绑定。
  • @HansPassant,查看我更新的帖子。
  • 你的根对象有没有可能是某种通用集合或容器?正如here 所提到的,这些并不总是与sgen 程序集配合得很好。
  • @dbc,不,不是。
  • 我也会使用 procmon 和监视文件。它会找到序列化程序程序集,但可能需要一些时间才能找到它。

标签: c# serialization xml-serialization xmlserializer sgen


【解决方案1】:

为了提高 XML 序列化的性能,每次为特定类型首次实例化 XmlSerializer 时都会动态生成程序集。它在应用程序生命周期中只发生一次,但这会使其第一次使用速度变慢。

当您实例化 XmlSerializer 时,您必须传递您将尝试使用该序列化程序实例进行序列化和反序列化的对象的类型。序列化程序检查 Type 的所有公共字段和属性,以了解实例在运行时引用的类型。然后,它继续为一组类创建 C# 代码,以使用 System.CodeDOM 命名空间中的类处理序列化和反序列化。在此过程中,XmlSerializer 检查 XML 序列化属性的反射类型,以根据 XML 格式定义自定义创建的类。 这些类随后被编译成一个临时程序集,并由 Serialize() 和 Deserialize() 方法调用以执行 XML 到对象的转换。

完整内容:Troubleshooting Common Problems with the XmlSerializer

更多信息:XmlSerializer Constructor Performance Issues

【讨论】:

  • 请仔细阅读我的问题。我已经使用sgen 来预编译那些第一次创建的程序集。问题是即使使用sgen 也没有任何区别。
【解决方案2】:

这是 x64 jit 编译器的一个已知问题,在某些情况下可能会非常慢。这就是为什么在代码已经编译后第二次运行反序列化时性能要好得多的原因。

尝试使用 .net 4.6 或更高版本,它具有新版本的 x64 jit 编译器 (RyuJIT)。如果无法更新 .net 版本,请查看此thread

【讨论】:

  • 我以前看过那个帖子;但是 Sgen.exe 不是应该预编译序列化程序程序集,因此不必即时编译吗?
  • sgen 会提前创建临时程序集,但仍然需要在运行时使用 jit 编译器进行编译。为避免这种情况,您必须使用 ngen 编译它。您是否尝试过升级 .net 或者这不是一个选项?
  • 我今天试试,然后告诉你。
  • 好的,所以我确实使用了.net 4.6.1,但它没有改变任何东西。此外,当我尝试使用 ngen.exe 安装程序集时,它给我一个错误提示“远程过程调用失败。”
  • 很奇怪,当我从 4.5 更新到 4.6.1 时,我的第一次运行速度提高了 20 倍以上。这个错误还有更多吗?您是否尝试在 project.dll 或 cls.xmlserializers.dll 上运行 ngen?您是否也考虑过使用不同的序列化程序?
猜你喜欢
  • 2012-01-27
  • 2013-01-31
  • 1970-01-01
  • 1970-01-01
  • 2023-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多