使用 DataContractSerializer 过滤大量 XmlNode 非常慢



考虑下面的代码

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 和内存?

在您的Deserialize方法中,我会formatter设为静态成员,因为它每次都是一样的(我不确定它在内部缓存)。然后使用.ReadObject(new StringReader(rawXml))来节省引入XmlReader的额外复杂性。

然后它变得棘手。尽量不要使用异常处理来控制你的逻辑,所以先做一些其他检查,而不是让它抛出并捕获它。

最后,我认为最大的胜利是不要采取XmlNodeList,而是采取Stream并创建一个XmlReader来扫描XML,并且仅在需要时反序列化所需的内容。拥有所有这些对象图的前期成本将迅速增加。

编辑:另一个建议,将签名更改为IEnumerable<CustomConversionData>yield return您要执行.Add(...)的位置,这样消耗代码可以流式传输结果,从而降低峰值内存使用量。

编辑2:每次都先选择ParentNode让我感到奇怪。如果XmlNodeList来自.ChildNodes调用,那么您将一遍又一遍地反序列化相同的内容。如果它来自SelectNodes("...")那么您可能能够更明智地选择具有XPath的正确节点,而不必获取父节点。如果您仍然需要这样做,请在此处创建一个XmlReader,检查元素名称,然后从中决定是否需要父级。如果您有正确的元素,则可以将XmlReader传递到Derserialize,保存另一个副本。

相关内容

  • 没有找到相关文章

最新更新