首頁  >  文章  >  後端開發  >  XML資料讀取方式效能比較(二)

XML資料讀取方式效能比較(二)

黄舟
黄舟原創
2017-02-13 15:45:241642瀏覽

 話說上期概括了一下通用的xml讀取方式,不過平時我們未必要用到XML源的全部數據,所以我又實驗了一下讀取部分數據的情況,比如根據標題的開頭字母,出現位置進行篩選。

  對於三種隨機讀取方式來說,只要改變查詢條件即可

  

XmlDocument:
var nodeList = doc.DocumentElement.SelectNodes("item[substring(title,1,1)='M'][position() mod 10 = 0]");
  XPathNavigator:
var nodeList = nav.Select("/channel/item[substring(title,1,1)='M'][position() mod 10 = 0]");
  Xml Linq:
var nodelist = from node in xd.XPathSelectElements("/channel/item[substring(title,1,1)='M'][position() mod 10 = 0]")

  使用XPath,只要改一行程式碼。 XPath也相當容易掌握,比SQL簡單許多。可以參考W3C Shcool的語法介紹以及MSDN 針對XPath用戶的LINQ To XML,一刻鐘功夫你就能掌握其中奧秘。

  但對XmlReader方式,可沒那麼容易了,同樣是讀title以M開頭,每十項取一項,想了半天,楞是沒想出個優雅點的實現方式,只好如此:

代碼

static List<Channel> testXmlReader2()
{
    var lstChannel = new List<Channel>();
    var reader = XmlReader.Create(xmlStream);
    int n = 0;Channel channel = null;
Search:
    while (reader.Read())
    {
        if (reader.Name == "item" && reader.NodeType == XmlNodeType.Element)
        {  
            while (reader.Read())
            {
                if (reader.Name == "item") break;
                if (reader.NodeType != XmlNodeType.Element) continue;
                switch (reader.Name)
                {
                    case "title":
                        var title = reader.ReadString();
                        if (title[0] != &#39;M&#39;) goto Search;          
                        n++;
                        if (n % 10 != 0) goto Search; 
                        channel = new Channel();
                        channel.Title = title;
                        break;
                    case "link":
                        channel.Link = reader.ReadString();
                        break;
                    case "description":
                        channel.Description = reader.ReadString();
                        break;
                    case "content":
                        channel.Content = reader.ReadString();
                        break;
                    case "pubDate":
                        channel.PubDate = reader.ReadString();
                        break;
                    case "author":
                        channel.Author = reader.ReadString();
                        break;
                    case "category":
                        channel.Category = reader.ReadString();
                        break;
                    default:
                        break;
                }
                lstChannel.Add(channel);
            }
        }
    }
    return lstChannel;
}

  可以看到,程式碼結構發生了明顯變化。為了作條件篩選,只得增加局部變數n,調整了實體類別初始化,和加入集合語句的所在位置,甚至被迫用了遺忘多年的goto語句進行跳轉(VB還好些)。業務邏輯滲透了程式碼細節的實現,用老趙的話說就是,一陣語法噪音的氣息撲面而來。

  XmlTextReader的實作代理類XmlTextReaderImp(internal的,不能直接用),是個有上萬行程式碼超級類,封裝了大量直接對Xml字元級進行的操作。由於操作很接近底層,宏觀很難找到太好的程式碼最佳化方式。如果篩選條件,也就是業務邏輯再複雜一點,程式碼就會面目全非,可理解性可維護性如鏡花水月。

  現在再來比較一下時間性能:

XmlDocment    26ms    
XPathNavigator    26ms    
XmlTextReader    20ms    
Xml Linq    28ms

  四種方式數據變得接近了,Document和Navigator消耗時間大幅下降,Reader方式下降不多,因為仍然要從頭Read到底,減少的3ms可以認為由於減少了實體物件所建立的開銷。比較蹊蹺的是Linq方式,居然沒有變化,落在了最後。

  可以測試不同的查詢條件,能看出這四種方式各有其效能極限,與Xml來源的大小有關。例如前兩種方式,就取決於XmlDocument.Load方法執行時間,在我本機上,Load這個Xml就需要23ms。 Linq方式也不是雷打不動,如果處理的結果很少,執行時間會降1~2毫秒。

  Document和Navigator方式,效能會隨資料量增加而明顯下降。很容易猜到,是因為它們創造了許多無用物件的緣故。看一下各方式記憶體佔用便知,在資料全部載入不篩選情況下,Document方式佔用了23.3M左右的內存,而Navigator方式只要22.9M左右,這也解釋了為什麼Document方式效能下降更明顯。 Reader方式資料全加載,只要20.1M左右內存,除去程式啟動本身的開銷,較前兩種內存佔用不到一半。 Linq方式在記憶體上又有驚艷表現,只比Reader方式多佔了不到500k。

  進一步的分析,得出了進一步的結論:除非有特別需要,慎用XmlTextReader,它對變化準備不足,容易出錯。更強烈建議使用Linq方式,雖然某些情況下時間性能略低於Navigator方式,但優異的記憶體佔用表現,奠定了它的首選地位。而且我相信,未來的Linq To XML,還會更強大。

以上就是XML資料讀取方式效能比較(二)的內容,更多相關內容請關注PHP中文網(www.php.cn)!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn