Linq到对象花费更多时间的性能问题

本文关键字:时间 性能 问题 对象 Linq | 更新日期: 2023-09-27 18:08:53

我有一个基于对象值更新的xml代码。这里的"foreach"循环大约需要12-15分钟来获取一个200kb的xml文件。请建议我如何提高性能。(XML文件由四个级别的标记组成,其中子(第4级)标记的编号各为10)

代码:

IEnumerable<XElement> elements = xmlDoc.Descendants();
foreach (DataSource Data in DataLst)
{ 
    XElement xmlElem = (from xmlData in elements
                        where Data.Name == xmlData.Name.LocalName  //Name
                           && Data.Store == xmlData.Element(XName.Get("Store", "")).Value
                           && Data.Section == xmlData.Element(XName.Get("Section", "")).Value
                        select xmlData.Element(XName.Get("Val", ""))).Single();
    xmlElem.ReplaceWith(new XElement(XName.Get("Val", ""), Data.Value));
} 

Linq到对象花费更多时间的性能问题

看起来这里有一个O(n)&乘以O(m)的问题,因为n = DataList的大小,m = xml的大小。为了使它变成O(n)+O(m),你应该对数据进行索引;例如:

var lookup = elements.ToLookup(
       x => new {
            Name = x.Name.LocalName,
            Store = x.Element(XName.Get("Store", "")).Value,
            Section =  x.Element(XName.Get("Section", "")).Value},
       x =>  x.Element(XName.Get("Val", ""))
    );
foreach (DataSource Data in DataLst)
{ 
    XElement xmlElem = lookup[
          new {Data.Name, Data.Store, Data.Section}].Single();
    xmlElem.ReplaceWith(new XElement(XName.Get("Val", ""), Data.Value));
}

(未测试-仅显示一般方法)

我认为更好的方法是将XML反序列化为c#类,然后使用LINQ,应该很快。

"感谢大家的宝贵时间和努力"

问题答案:实际上对象'DataLst'的类型是IEnumerable<>这需要时间来获取值,但在我将其更改为列表<>类型后,性能大大提高(现在在20秒内运行)

如果运行这个需要这么长时间,那么也许可以这样做:

  1. 不要同时迭代—只迭代xml文件和从DataLst中加载数据(使用sql命令或简单的linq语句加载基于Name/Store/Section的数据),使用此数据(Name/Store/Section)为键创建一个简单的结构/类—不要忘记实现equals,和GetHashCode
  2. 遍历XML-Elements,并使用字典查找要替换
  3. 的值。

这样,您只需迭代xml文件一次,而不是对数据源中的每个数据迭代一次。

不清楚为什么要花那么长时间-这是一个非常很长的时间。DataLst中有多少元素?为了简单起见,我将重写查询,以though开头:

IEnumerable<XElement> elements = xmlDoc.Descendants();
foreach (DataSource data in DataLst)
{ 
    XElement valElement = (from element in xmlDoc.Descendants(data.Name)
                           where data.Store == element.Element("Store").Value
                              && data.Section == element.Element("Section").Value
                           select element.Element("Val")).Single();
    valElement.ReplaceWith(new XElement("Val"), data.Value));
} 

(顺便说一下,我假设您的元素实际上都没有名称空间。)

下一步:考虑替换valElement内容而不是替换元素本身。改为:

valElement.ReplaceAll(data.Value);

现在,这一切都是为了保持简单性,避免预计算等…因为它听起来不应该花这么长时间。但是,您可能需要按照Marc和Carsten的建议构建查找。

尝试将LINQ中的Single()调用替换为First()

冒着着火的风险,您考虑过用XQuery来编写这个吗?一个不错的XQuery处理器很有可能有一个连接优化器来有效地处理这个查询。