在调用一个拥有大量字段的类进行简单的XmlSerializer.Deserizlize()操作时,我遇到了非常严重的性能损失。
注意:我是在家里没有使用Visual Studio编写代码,所以可能会出现一些错误。
我的可序列化类是扁平的,并且拥有数百个字段:
[Serializable]
class Foo
{
public Foo() { }
[XmlElement(ElementName = "Field1")]
public string Field1;
// [...] 500 Fields defined in the same way
[XmlElement(ElementName = "Field500")]
public string Field500;
}
我的应用程序反序列化一个输入字符串(甚至是小字符串):
StringReader sr = new StringReader(@"<Foo><Field1>foo</Field1></Foo>");
XmlSerializer serializer = new XmlSerializer(typeof(Foo));
object o = serializer.Deserialize(sr);
在32位系统中运行应用程序(或使用corflags.exe强制为32位),第一次执行代码需要约1秒钟(生成临时序列化类,等等...),然后接近于0。
在64位系统中运行应用程序,第一次执行代码需要1分钟,然后接近于0。
是什么导致了这么长时间的系统挂起,在64位系统中首次执行XmlSerializer对于一个大类进行序列化时?
现在我不确定是要归咎于临时类的生成/删除、xml名称表初始化、CAS、Windows搜索、防病毒软件还是圣诞老人...
剧透警告
这里是我的测试结果,请勿阅读如果不想被我的(可能)分析错误转移注意力。
- 在Visual Studio调试器中运行代码使得代码在64位系统下也运行快速
- 添加(完全没有文档说明的)system.diagnostic开关"XmlSerialization.Compile",它会防止系统删除序列化临时类,使得代码即使在64位系统下也运行快速
- 获取运行时创建的临时FooXmlSerializer类,包括.cs文件在我的项目中,使用它代替XmlSerializer,使得代码即使在64位系统下也运行快速
- 使用sgen.exe创建相同的FooXmlSerializer类,包括.cs文件在我的项目中,使用它代替XmlSerializer,使得代码即使在64位系统下也运行快速
- 使用sgen.exe创建相同的FooXmlSerializer类,将Foo.XmlSerializers.dll程序集引用到我的项目中,并使用它代替XmlSerializer,使得代码在64位系统中运行缓慢(这让我非常困扰)
- 仅当输入的反序列化内容实际包含大类的字段时,性能损失才会发生(这也让我非常困扰)
更进一步解释最后一点,如果我有一个类:
[Serializable]
class Bar
{
public Bar() { }
[XmlElement(ElementName = "Foo")]
public Foo Foo; // my class with 500 fields
}
只有在传递一个Foo子对象时,反序列化才会变慢。即使我已经执行了反序列化操作:
StringReader sr = new StringReader(@"<Bar></Bar>");
XmlSerializer serializer = new XmlSerializer(typeof(Bar));
object o = serializer.Deserialize(sr); // FAST
StringReader sr = new StringReader(@"<Bar><Foo><Field1>foo</Field1></Foo></Bar>");
XmlSerializer serializer = new XmlSerializer(typeof(Bar));
object o = serializer.Deserialize(sr); // SLOW
编辑 我忘了说,我用进程监视器分析了执行过程,我没有看到任何来自我的应用程序或csc.exe的长时间任务,也没有看到任何与框架相关的内容。系统只是在做其他事情(或者我漏掉了什么),比如杀毒软件、explorer.exe、Windows搜索索引(已经尝试关闭它们)。