在对包含大量字段的类调用简单的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位),代码首次执行 ONE SECOND (临时序列化类生成,所有...),然后它接近于0.
在64位系统中运行应用程序,代码第一次一分钟,然后接近0。
在第一次执行XmlSerializer期间,对于64位系统中的大型类,可能会将系统挂起这么长时间
现在我不确定是否必须责怪临时类生成/删除,xml名称表初始化,CAS,Windows搜索,AntiVirus或圣诞老人......
SPOILERS
以下是我的测试,如果您不想被我(可能的)analysys错误所牵制,请不要阅读此内容。
为了进一步解释最后一点,如果我有一个班级:
[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
编辑我忘了说我用Process Monitor分析了执行情况,我没有看到任何需要花费很长时间从我的应用程序或csc.exe或任何与框架相关的任务。系统只做其他事情(或者我遗漏了一些东西),比如防病毒,explorer.exe,Windows搜索索引(已经尝试关闭它们)
答案 0 :(得分:9)
我不知道这是否相关,但我遇到了XSLT的问题,并且微软发现those rather interesting comments有关64位JITter的信息:
问题的根源与两件事有关:首先,x64 JIT编译器有一些二次缩放的算法。其中一个是调试信息生成器,不幸的是。因此,对于非常大的方法,它确实失控。
[...]
64位JIT中的一些具有多项式缩放的算法。我们实际上正在努力将32位JIT编译器移植到x64,但是直到下一个并行释放运行时才能看到它的亮点(如“2.0&amp; amp; ; 4.0并排运行,但3.0 / 3.5 / 3.5SP1是'就地'版本。。我已将其转换为“建议”,因此我可以将其附加到JIT吞吐量工作项确保在新移植的JIT准备出货时修复此问题。
同样,这是一个完全不同的问题,但在我看来,64位JITter评论是通用的。
答案 1 :(得分:6)
<强>更新强>:
我能够重现这一点,调查显示大部分时间花在了JIT编译器上:
JittingStarted:“Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderFoo”,“Read2_Foo”,“instance class SerializersTester.Foo”
您可以轻松证明没有任何分析器工具。
您可以注意到与x86程序集相比,x64生成速度要慢得多
确切的原因隐藏在x64 JIT内部(BTW与x86完全不同),遗憾的是我没有足够的空余时间来找到它。
为了避免这种性能损失,您可以通过sgen生成序列化程序的程序集,引用它并在最终用户PC上的应用程序设置期间通过ngen编译为本机映像。
答案 2 :(得分:3)
澄清“XmlSerialization.compile”这就是它发生的事情:
如果我们在64位上运行没有.config文件的代码,那就慢了。
如果我们将以下部分添加到应用程序的.config文件中
<configuration>
<system.diagnostics>
<switches>
<add name="XmlSerialization.Compilation" value="4"/>
</switches>
</system.diagnostics>
</configuration>
结果如下:
也许在调试模式下创建DLL(因为有可用的PDB文件)改变了JIT编译器的行为,使其再次快速...
答案 3 :(得分:0)
来自MSFT: “x64 JIT编译器有一些算法可以进行二次缩放....自从2005年第一次发布64位框架以来,我们已经看过很多次了。” 和
“这个问题是a)已知,并且b)不是很容易解决。这是64位JIT的设计问题。我们正处于更换64位JIT实现的早期阶段,因此它将< em>最终获取地址,但遗憾的是,不是在CLR 4.0时间范围内。“