我们的应用程序正在读取一些XML文件。 XML格式是固定的,因此我们可以使用XmlSerializer非常轻松地阅读它们。
我使用此代码读取XML文件并将其转换为类:
public static T FromXml<T>(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)在正手上生成该程序集来规避。这将时间减少到大约一半。主要是由于装配的阅读和反射。
我希望进一步优化这一点,方法是将XmlSerializer
类放在程序集中的实际类中,但我找不到让XmlSerializer
的方法知道不要读取外部组件,而是使用当前组件中的序列化器。
有任何想法如何做到这一点或另一种方法来使这项工作? (我无法预加载它们,因为大多数序列化类在启动时使用)
使用ANTS Profiler进行分析(来自其他机器的指标,但模式相同):
平原。在生成和加载XmlSerializer程序集时,大多数时间(300ms + 400ms = 700ms)都会丢失。
用sgen生成程序集。大多数情况下(336ms)在加载XmlSerializer程序集时会丢失。
当在项目中包含程序集的实际源代码并直接调用序列化程序时,操作将降至456ms(首先是1s,第二次是556ms)。
答案 0 :(得分:3)
注意: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<UserSettings>(File.ReadAllText("settings.json"))
答案 1 :(得分:2)
除非你在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代码在单独的程序集中,那么您的分析似乎表明没有太大区别,而加载似乎是瓶颈。我想知道它们在同一个组件中的情况如何?