【问题标题】:Improve performance of XmlSerializer提高 XmlSerializer 的性能
【发布时间】:2012-03-19 03:07:03
【问题描述】:

我使用XmlSerializer 来序列化/反序列化一些对象。问题是性能。分析时,使用XmlSerializer 使我们的应用程序启动时间延长 2 秒。我们缓存我们的 XmlSerializer 并重用它们。我们无法使用 sgen.exe,因为我们正在使用 XmlAttributeOverrides 创建 XmlSerializer。

我尝试使用 Json.Net 之类的序列化替代方案,一开始效果很好。问题是我们需要向后兼容,所以所有已经生成的 xml 都需要正确解析。此外,对象序列化输出必须是 Xml。

总结一下:

  1. 我收到了由 XmlSerializer 序列化的 Xml 数据。
  2. 我需要反序列化 Xml 数据并将其转换为对象。
  3. 我需要将对象序列化为 Xml(理想情况下是一种 Xml 格式,就像 XmlSerializer 所做的那样)

【问题讨论】:

  • 您的 XML 数据包含开始标记 <UsernameHistory> 和结束标记 </DatastoreHistory>。我想这是一个打字错误。此外,在您的问题中,您定义了输入数据的格式,但不清楚定义 JSON 输出的格式。就像您可以用不同的 XML 格式表示相同的信息一样,您可以使用等效的信息集生成不同的 JSON 数据,但格式不同。我认为您应该更清楚地定义输出数据的格式。
  • 如果您还清除限制“我不能使用 XmlSerializer”会很好。如果只是性能的原因,那么有很多方法可以提高性能,使用sgen.exe或者实现ISerializable接口。问题中最不清楚的是:为什么如果数据输入格式如此奇怪。您有一个长的 XML 文件还是有很多这样的文件?通常一个人在数据库中有原始信息。那么为什么你需要这么奇怪的 XML 输入而不是访问 original 数据呢?
  • 我更新了我的问题以更多地代表问题
  • 这只是 XmlSerializer 的启动时间问题吗?正如 Oleg 所说,如果使用得当,序列化/反序列化时间可能会非常快(已编译),例如,如果调用了良好的构造函数等。
  • 是的,它只是在启动时,因为在启动时我们正在反序列化我们的对象。构建 XmlSerializer 需要时间。之后,速度很快,但我们需要改进启动时间。

标签: c# xml serialization json.net


【解决方案1】:

最终,这取决于模型的复杂性。 XmlSerializer 需要做很多思考,而且花费这么长时间的事实让我怀疑你的模型非常复杂。对于 simple 模型,可能可以使用 LINQ-to-XML 手动实现反序列化(非常简单),甚至可能是 XmlReader(如果您感觉很勇敢 - 它不是容易得到 100% 正确)。

但是,如果模型很复杂,这是一个问题,坦率地说,在引入细微错误方面会非常冒险。

另一个选项是DataContractSerializer,它处理xml,但不如XmlSerializer,当然也没有对布局有太多的控制。我强烈怀疑DataContractSerializer 不会帮助你。

据我所知,XmlSerializer 没有直接替代品,如果 sgen.exe 不是一个选项,我相信您基本上可以选择:

  • 忍受它
  • 自己重写XmlSerializer,不知怎的比他们做得更好
  • 使用 LINQ-to-XML 之类的东西并接受所涉及的工作

从长远来看,我会说“切换格式”,并且仅将 xml 用于旧版导入。我碰巧知道一些非常快的二进制协议,它们很容易在 ;p

中替代

【讨论】:

  • 优秀的答案。我不得不在一个项目中做类似的事情,我必须使用接口而不是使用抽象类(因为 C# 不做多重继承)。使用 linq to xml 和反射就可以了。我的下一个任务是制作属性而不是参数中的规则列表(刚刚了解了这一点)。我必须说这很有趣。
【解决方案2】:

问题是您正在请求 sgen 未涵盖的类型,这会导致在启动期间生成新的程序集。

您可以尝试获取由 Xmlserializer 为您的特定类型生成的临时文件,并将此代码用于您自己的预置 xmlserializer 程序集。 我使用了这个 approach to find out why csc.exe 被执行,它确实延迟了我的应用程序的启动。

除此之外,重命名文章中的某些类型可能会有所帮助,以达到 sgen 创建的相同类型名称以便能够使用 sgen。通常类型数组不是由 sgen 预先创建的,这有时很可惜。但是,如果您将类命名为 ArrayOf HereGoesYourTypeName,那么您将能够使用预生成的程序集。

【讨论】:

    【解决方案3】:

    您必须使用经典的 .net 序列化来反序列化您的列表

    类似于以下内容:

    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 的情况下处理由 XmlSerializer 序列化的 Xml...
    【解决方案4】:

    如果您以无法使用的格式存储 xml,则使用 xslt 将其转换为您可以使用的格式。

    如果此 xml 以 XmlSerializer 格式存储 - 比如说在平面文件中 - 或 db - 那么您可以在其上运行一次转换,而不会在您通常的运行时产生 XmlSerializer 开销。

    或者,您可以在运行时对其进行 xslt - 但我怀疑这会比 Massimiliano 概述的方法更快。

    【讨论】:

      【解决方案5】:

      This 回答有一些很好的信息,说明为什么 XmlSerializer 使用 XmlAttributeOverrides 运行缓慢。

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

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

      如果它是一个 GUI 应用程序,您可以添加一个启动屏幕来隐藏延迟(或俄罗斯方块游戏!!)

      如果所有其他方法都失败了,您不能通过运行现有的反序列化和 JSON 序列化将现有文件转换为 JSON,还是有硬性要求将它们保留为 XML?

      【讨论】:

        【解决方案6】:

        您可以使用线程或任务来让应用程序更快启动,而无需等待硬盘驱动器或反序列化。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-02-19
          • 2019-03-26
          • 1970-01-01
          • 2014-04-18
          • 2014-01-04
          • 2021-10-31
          • 1970-01-01
          相关资源
          最近更新 更多