考虑以下代码
List<CustomConversionData> Filter(XmlNodeList nodeList)
{
var filteredResults= new List<CustomConversionData>();
//Deserailze the data:
foreach (XmlNode item in nodeList)
{
try
{
CustomConversionData obj = Deserialize<CustomConversionData>(item.ParentNode.OuterXml);
filteredResults.Add(obj);
}
catch
{
try
{
CustomConversionData obj = Deserialize<CustomConversionData>(item.OuterXml);
filteredResults.Add(obj);
}
catch (Exception e) {
}
}
}
return filteredResults;
}
以及进行反序列化的方法
public T Deserialize<T>(string rawXml)
{
using (XmlReader reader = XmlReader.Create(new StringReader(rawXml)))
{
DataContractSerializer formatter =
new DataContractSerializer(typeof(T));
return (T)formatter.ReadObject(reader);
}
}
当我为包含8000个节点的nodeList
运行此操作时,大约需要6个小时。我正在寻找一种方法来减少这个时间,并且在开始时我想也许我可以为每次迭代创建一个任务,但它变得比以前慢,我认为这是因为在任务之间切换的开销。
我想知道什么是改善此代码性能的最佳方法,因为它似乎非常占用CPU和内存?
答案 0 :(得分:2)
在Deserialize
方法中,我会使formatter
成为静态成员,因为它每次都是相同的(我不确定它是否在内部缓存)。然后使用.ReadObject(new StringReader(rawXml))
来节省引入XmlReader
的额外复杂性。
然后它变得棘手。尽量不要使用异常处理来控制你的逻辑,所以先做一些其他检查,而不是让它抛出并捕获它。
最后,我认为最大的胜利是不采用XmlNodeList
,而是采用Stream
并创建XmlReader
来扫描XML并仅反序列化所需内容,什么时候需要它。拥有所有这些对象图的前期成本将快速增加。
修改:另一个建议,将签名更改为IEnumerable<CustomConversionData>
和yield return
,这样您可以执行.Add(...)
,这样消费代码就可以对结果进行流式传输,从而保持峰值内存使用率下降。
Edit2:每次首先选择ParentNode
为奇数。如果XmlNodeList
来自.ChildNodes
来电,那么您将一遍又一遍地反序列化相同的内容。如果它来自SelectNodes("...")
那么您可能能够更聪明地选择正确的节点与XPath开始而不必获得父节点。如果您仍然需要这样做,请在此处创建XmlReader
,检查元素名称,并从中确定是否需要父项。如果你有正确的元素,那么你可以将XmlReader
传递给Derserialize
,保存另一个副本。