如果你使用的平台是.NET 3.5,在操作XML文件時會有三種選擇: LINQ to XML, LINQ to XML with XPath以及傳統的XmlDocument。既然有三種選擇,排除個人主觀偏好,想知道哪一種做法的效能最好呢?

之前有個迷思,一直覺得LINQ表達方式友善,理論上會付出效能上的代價(正所謂有一好沒兩好)。所以有時針對複雜的元素查詢,我會using System.Xml.XPath,然後改用XPathSelectElements()查詢,直到無意間發現了一篇談LINQ to XML與XPath Benchmark的文章,才發現我錯了。該文作者試了一個120,000筆資料, 54MB大小的XML檔案,LINQ to XML用LINQ語法查詢,竟比叫用XPathSelectElements()快了五倍!!

我自己也做了一個測試,產生一個36M大小20,000 * 100個Node的XML文件,分別用LINQ to XML, XPathSelectElements及XmlDocument.SelectNodes去查詢同樣條件,統計Node數。依我的測試結果,也驗證了LINQ to XML確實比XPathSelectElements來得快,至於XmlDocument,我們就忘了它吧...

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml.Linq;
using System.Diagnostics;
using System.Xml.XPath;
using System.Xml;
 
namespace TestXmlPerformance
{
    class Program
    {
        static void GenSampleXml()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("<root>");
            Random rnd = new Random();
            for (int i = 0; i < 20000; i++)
            {
                sb.AppendFormat("<pack id=\"{0}\">", i);
                for (int j = 0; j < 100; j++)
                    sb.AppendFormat("<item model=\"{0}\" />",
                        rnd.Next(20));
                sb.Append("</pack>");
            }
            sb.Append("</root>");
            File.WriteAllText(".\\Sample.xml", sb.ToString());
        }
 
        static void Main(string[] args)
        {
            //GenSampleXml();
            {
                Stopwatch sw = new Stopwatch();
                sw.Start();
                XDocument xd = XDocument.Load(".\\Sample.xml");
                var q = from o in xd.Descendants("item")
                        where o.Attribute("model").Value == "7"
                        select o;
                Console.WriteLine(q.Count());
                sw.Stop();
                Console.WriteLine("Test 1: {0}ms", 
                    sw.ElapsedMilliseconds);
            }
 
            {
                Stopwatch sw = new Stopwatch();
                sw.Start();
                XDocument xd = XDocument.Load(".\\Sample.xml");
                Console.WriteLine(
                    xd.XPathSelectElements("root/pack/item[@model='7']")
                    .Count()
                );
                sw.Stop();
                Console.WriteLine("Test 2: {0}ms", 
                    sw.ElapsedMilliseconds);
            }
 
            {
                Stopwatch sw = new Stopwatch();
                sw.Start();
                XmlDocument xd = new XmlDocument();
                xd.Load(".\\Sample.xml");
                Console.WriteLine(
                    xd.DocumentElement
                    .SelectNodes("pack/item[@model='7']").Count
                );
                sw.Stop();
                Console.WriteLine("Test 3: {0}ms", 
                    sw.ElapsedMilliseconds);
            }
 
            Console.Read();
        }
    }
}

【 測試數據 】

100507
Test 1: 3268ms
100507
Test 2: 3960ms
100507
Test 3: 9246ms


Comments

# by ina2588

感謝指導.可惜試了一下還是躲不開網路遠端xml讀取的gui延遲.backgroundWorker還是要用.

# by Ernest

黑大, 請教一下 如果想用ASP.NET + LINQ 運行一個SQL SP, 而該SP 一行就是10-15分鐘, 有可能不TIME OUT 嗎? 我可能怎樣做?

# by Jeffrey

to Ernest, DataContext有個CommandTimeout屬性(單位: 秒),把值加大應該就可以解決。http://msdn.microsoft.com/zh-tw/library/system.data.linq.datacontext.commandtimeout.aspx

Post a comment


31 + 11 =