代码之家  ›  专栏  ›  技术社区  ›  Nasser Hadjloo

性能:xmlReader或linq to xml

  •  9
  • Nasser Hadjloo  · 技术社区  · 14 年前

    我有一个150MB的XML文件,在我的项目中用作数据库。目前我正在使用 XmlReader 从中读取内容。我想知道它是否更好用 XMLRead 或此方案的Linq to XML。

    请注意,我正在这个XML中搜索一个项目,并显示搜索结果,因此可能需要很长时间或很短时间。

    3 回复  |  直到 7 年前
        1
  •  9
  •   Bob Bryan    7 年前

    如果需要性能,请使用xmlreader。它不会读取整个文件并在内存中构建DOM树。相反,它从磁盘读取文件,并返回在路上找到的每个节点。

    通过快速的谷歌搜索,我发现了xmlReader、linqtoxml和xdocument.load的性能比较。

    https://web.archive.org/web/20130517114458/http://www.nearinfinity.com/blogs/joe_ferner/performance_linq_to_sql_vs.html

        2
  •  8
  •   Michael    11 年前

    我个人会考虑使用linq-to-xml,使用Microsoft帮助文件中概述的流技术: http://msdn.microsoft.com/en-us/library/system.xml.linq.xstreamingelement.aspx#Y1392

    下面是一个使用简单过滤器从200MB XML文件读取的快速基准测试:

    var xmlFilename = "test.xml";
    
    //create test xml file
    var initMemoryUsage = GC.GetTotalMemory(true);
    var timer = System.Diagnostics.Stopwatch.StartNew();
    var rand = new Random();
    var testDoc = new XStreamingElement("root", //in order to stream xml output XStreamingElement needs to be used for all parent elements of collection so no XDocument
        Enumerable.Range(1, 10000000).Select(idx => new XElement("child", new XAttribute("id", rand.Next(0, 1000))))
    );
    testDoc.Save(xmlFilename);
    var outStat = String.Format("{0:f2} sec {1:n0} kb //linq to xml ouput streamed", timer.Elapsed.TotalSeconds, (GC.GetTotalMemory(false) - initMemoryUsage) / 1024);
    
    //linq to xml not streamed
    initMemoryUsage = GC.GetTotalMemory(true);
    timer.Restart();
    var col1 = XDocument.Load(xmlFilename).Root.Elements("child").Where(e => (int)e.Attribute("id") < 10).Select(e => (int)e.Attribute("id")).ToArray();
    var stat1 = String.Format("{0:f2} sec {1:n0} kb //linq to xml input not streamed", timer.Elapsed.TotalSeconds, (GC.GetTotalMemory(false) - initMemoryUsage) / 1024);
    
    //xmlreader
    initMemoryUsage = GC.GetTotalMemory(true);
    timer.Restart();
    var col2 = new List<int>();
    using (var reader = new XmlTextReader(xmlFilename))
    {
        while (reader.ReadToFollowing("child"))
        {
            reader.MoveToAttribute("id");
            int value = Convert.ToInt32(reader.Value);
            if (value < 10)
                res2.Add(value);
        }
    }
    var stat2 = String.Format("{0:f2} sec {1:n0} kb //xmlreader", timer.Elapsed.TotalSeconds, (GC.GetTotalMemory(false) - initMemoryUsage) / 1024);
    
    //linq to xml streamed
    initMemoryUsage = GC.GetTotalMemory(true);
    timer.Restart();
    var col3 = StreamElements(xmlFilename, "child").Where(e => (int)e.Attribute("id") < 10).Select(e => (int)e.Attribute("id")).ToArray();
    var stat3 = String.Format("{0:f2} sec {1:n0} kb //linq to xml input streamed", timer.Elapsed.TotalSeconds, (GC.GetTotalMemory(false) - initMemoryUsage) / 1024);
    
    //util method
    public static IEnumerable<XElement> StreamElements(string filename, string elementName)
    {
        using (var reader = XmlTextReader.Create(filename))
        {
            while (reader.Name == elementName || reader.ReadToFollowing(elementName))
                yield return (XElement)XElement.ReadFrom(reader);
        }
    }
    

    下面是我机器上的处理时间和内存使用情况:

    11.49 sec 225 kb      // linq to xml ouput streamed
    
    17.36 sec 782,312 kb  // linq to xml input not streamed
    6.52 sec 1,825 kb     // xmlreader
    11.74 sec 2,238 kb    // linq to xml input streamed
    
        3
  •  2
  •   Martin Milan    14 年前

    写一些基准测试来准确地确定情况对你来说是什么,然后从那里开始…Linq2XML引入了很多灵活性…