性能优化使用生成的XmlSerializer类

我们的应用程序正在读取一些XML文件。 XML格式是固定的,因此我们可以使用XmlSerializer非常容易地读取它们。

我使用此代码读取XML文件并将其转换为类:

public static T FromXml(this string xml) where T : class { if (string.IsNullOrEmpty(xml)) { return default(T); } XmlSerializer xmlserializer = new XmlSerializer(typeof(T)); XmlTextReader textReader = new XmlTextReader(new StringReader(xml)); textReader.Normalization = false; XmlReaderSettings settings = new XmlReaderSettings(); T value; using (XmlReader reader = XmlReader.Create(textReader, settings)) { value = (T)xmlserializer.Deserialize(reader); } return value; } 

但是,存在一些性能问题。 当第一次调用此代码时,使用T的特定类型, XmlSerializer生成Project.XmlSerializer.dll文件。

这很好,但花费了一些宝贵的毫秒(在我的情况下大约900毫秒)。 这可以通过使用XML Serializer Generator(sgen)在正手上生成该程序集来规避。 这将时间减少到大约一半。 主要是由于assembly的读取和reflection。

我希望通过将XmlSerializer类放在实际类所在的程序集中进一步优化它 ,但我找不到让XmlSerializer知道不读取外部程序集的方法,而是使用当前程序集中的序列化程序。

有任何想法如何做到这一点或另一种方法使这项工作? (我无法预加载它们,因为大多数序列化类在启动时使用)


使用ANTS Profiler进行分析(来自其他机器的指标,但模式相同):

在此处输入图像描述

平原。 在生成和加载XmlSerializer程序集时,大多数时间(300ms + 400ms = 700ms)都会丢失。

在此处输入图像描述

用sgen生成组件。 大多数情况下(336ms)在加载XmlSerializer程序集时丢失。

在此处输入图像描述

当在项目中包含程序集的实际源代码并直接调用序列化程序时,操作将降至456ms(首先是1s,第二次是556ms)。

除非你在app启动时进行序列化,否则一种方法是强制CLR加载甚至编译你正在使用的任何类,可能在一个线程中,一旦你开始就在后台运行你的应用。

比如,例如:

 foreach (Assembly a in assembliesThatShouldBeCompileed) foreach (Type type in a.GetTypes()) if (!type.IsAbstract && type.IsClass) { foreach (MethodInfo method in type.GetMethods( BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)) { if (method.ContainsGenericParameters || method.IsGenericMethod || method.IsGenericMethodDefinition) continue; if ((method.Attributes & MethodAttributes.PinvokeImpl) > 0) continue; System.Runtime.CompilerServices .RuntimeHelpers.PrepareMethod(method.MethodHandle); } } 

然而,奇怪的是,如果SGEN的代码在一个单独的程序集中,你的分析似乎表明没有太大的区别,而加载似乎是瓶颈。 我想知道它们在同一个组件中的情况如何?

注意:OP发布了一个示例配置: http : //pastebin.com/d67nch3R

基于示例配置和您遇到的问题类型,有几种蛮力的方式,几乎可以保证做到这一点,两者都完全放弃了XML序列化器

路线#1

放弃XML序列化并使用XDocument从XML中获取数据。

路线#2

使用json和Newtonsoft Json来存储和加载配置。 它应该比XML Serializer执行得更好

示例json对应物看起来像这样:

 { "Connections": { "-default": "Local\\SqlServer", "-forcedefault": "false", "group": { "-name": "Local", "connection": { "-name": "SqlServer", "database": { "-provider": "SqlServer", "-connectionString": "blah" } } } }, "LastLanguage": "en", "UserName": "un", "SavePassword": "true", "AutoConnect": "false", "Password": "someObfuscatedHashedPassword==", "ConnectionName": "Somewhere\\Database", "LastAvailableBandwidth": "0", "LastAvailableLatency": "0", "DateLastConnectionSuccesful": "2014-08-13T15:21:35.9663654+02:00" } 

并加载它:

 UserSettings settings = JsonConvert.DeserializeObject(File.ReadAllText("settings.json"))