靈魂-放水

          為學日益,為道日損。

          BlogJava 首頁 新隨筆 聯系 聚合 管理
            296 Posts :: 10 Stories :: 274 Comments :: 0 Trackbacks

          作者:Jimmy Zhang;rainy14f(作者的blog:http://shaofan.blogjava.net/)

          概要

          做為下一代WEB應用的推動性技術,XML相當簡單,易學易用。然而,當前的XML處理技術卻非如此。Document Object Model和Simple API for XML都比較慢,低效,且不易于使用。VTD-XML,作為下一代的XML處理模型,提供超越DOM和SAX的廣泛用途和更佳選擇,不僅可以簡化XML編程,也使選擇XML處理模型更加容易。這篇文章通過最近的基準測試數據和示例程序來突顯它的關鍵性的技術優勢,顯示出VTD-XML將可能解決長期以來困擾企業架構的,在DOM和SAX之間進行抉擇的問題。

          自從誕生以來的八年里,XML作為一個開放,半結構化的數據格式和WEB應用的數據交換工具,已取得了長足進步。由于它的簡易性和良好的可讀性,XML受到開發人員的熱烈歡迎,并且已經成為了企業架構不可分割的一部分。

          雖然很難說清XML到底有多少種不同的應用,但至少有一點是肯定的:XML解析處理已成為各種工作的先決任務。實際上,決定使用哪種解析器也經常是企業開發者在項目中必須首先解決的問題之一。長久以來,這其實就是在兩種 XML處理模型之間做出選擇:Document Object Model (DOM) 和 Simple API for XML (SAX)。

          粗看之下,DOM和SAX各自的優缺點剛好形成互補。DOM使用內存保存對象結構;而SAX則基于事件并且不使用內存來存儲任何數據。因此,DOM比較適合文檔較小而數據訪問模式復雜的情況,相反情況下,則使用SAX。

          然而事實卻并不這么單純。很多情況下,開發者不情愿使用復雜的SAX,但又不得不用,因為沒有其他選擇。此外,即使XML文件的大小只是稍微大于幾百K,DOM的內存開銷和性能遲滯也會成為棘手的障礙,使得程序無法達到項目所要求的最低性能目標。

          那么是否SAX的性能真得好得多?實際上,SAX所吹噓的解析性能――通常比DOM快幾倍――常常是不現實的。事實顯示,SAX笨拙的,只能往前的解析不僅在使用時相當不便,而且當文檔結構稍微復雜時,也會遇到性能問題。如果開發人員不想多次掃描文檔,那么就需要對文檔進行緩沖,或構建自己的對象模型。

          不管使用哪種方法,性能都會成為問題,正如Apache Axis所證明的那樣。在Axis的FAQ頁面,它聲稱使用了SAX來構建高性能的實現,但它仍然使用了他們自己的和DOM非常相像的對象模型。但與它的前任 (Apache SOAP) 相比,這種做法并沒有帶來明顯的性能提升。而且,SAX無法處理XPath,一般來說也無法驅動XSLT (Extensible Stylesheet Language Transformation) 的處理。因此,SAX仍然無法真正解決XML處理中的問題。

          為了尋找一個更易用的SAX的取代方案,越來越多的開發人員開使轉向StAX (Streaming API for XML)。與SAX相比,StAX使用從XML文件中提取標記的方法,而不是回調。這種方案顯著地改善了可用性,但一個基本的問題仍然存在――StAX的只能往前的解析對于程序員依然不便,而且存在隱藏的性能損失。

          底線是:任何想得到廣泛應用的XML處理模型,必需能夠完整體現XML的層次結構。這是因為,XML是被設計為在WEB上傳輸復雜數據的,因此完整展現它的結構信息也是它的任務之一。

          VTD-XML改變了游戲

          假設我們要從頭開始一個XML處理過程,并克服上面提到的DOM和SAX的種種缺點,那么這個新的模型應該具有以下屬性:

          * 隨機訪問能力:處理模型應該允許開發人員方便訪問文檔的某種層次結構,比如,使用XPath,或手動。
          * 高性能:性能上與DOM及SAX相比,應有顯著提高,而且這個“性能”應該是真實的,就是說,應該把建立文檔層次結構的時間也算上。
          * 低內存占用率:要使該模型能夠被廣泛應用于各種場景,不管文件的大小,那它就必須能夠以最低的內存消耗來表現XML的結構。

          VTD-XML就是一個實現了這些目標的下一代的開源XML處理模型。它相比于DOM和SAX有著本質和全面的改進。VTD-XML的一個關鍵優化是非提取符號(non-extractive tokenization)。在其內部,VTD-XML在內存中保存完整及未解碼的XML消息,并使用一個二進制編碼規范來唯一地表示每個符號。這種規范被稱為Virtual Token Descriptor(虛擬符號描述符)。每個VTD記錄都是一個64字節的整數,它對XML中符號的長度,起始偏移量,類型,嵌套深度進行了編碼。

          再簡單地介紹一下VTD-XML的歷史,也許你會感興趣:最初這個概念是被用來在特定硬件設備上使用,以使這些硬件(如路由器,交換機)可以高速處理XML,比如FPGA,ASIC。此后,VTD-XML項目組決定使它開源,并于2004年五月發布了VTD-XML的最初版本,0.5版,用JAVA實現。從那時起。VTD-XML經歷了多次改進并越來越成熟。在0.8版本中,C語言版本的VTD-XML與JAVA版同時發布。在1.0版中引入了對XPath的內建支持,于2005年10月發布。最新的版本是1.5版,它的解析引擎被重新編寫以實現更強的模塊化和更高的性能。

          同樣,在這個版本中還出現了一個新的特性,叫作緩沖重用。它的基本概念是,當XML應用需要通過網絡連接來反復地讀入XML文檔時,該應用會重用在第一次處理中分配的內存緩沖。換句話說,即一次分配,多次使用。就VTD-XML來講,這個特性完全消除了在處理XML過程中建立對象和垃圾回收的開銷(在DOM和SAX中占用50%至80%的開銷)。在該項目的網站上,提供有最新的軟件下載和深層技術說明。


          一個簡短例子

          為了使你更好地了解VTD-XML編程的風格,本文首先對用VTD-XML和DOM解析和訪問一個簡單的XML文件進行對比。該文件名為test.xml,內容如下:

          <purchaseOrder orderDate="1999-10-21">
          ?????? <item partNum="872-AA">
          ???????? <productName>Lawnmower</productName>
          ???????? <quantity>1</quantity>
          ???????? <USPrice>148.95</USPrice>
          ?????? </item>
          </purchaseOrder>



          VTD-XML版本的程序如下:

          import com.ximpleware.*;
          import com.ximpleware.parser.*;
          import java.io.*;

          public class use_vtd {
          ????public static void main(String[] args){
          ????????try{
          ????????????File f = new File("test.xml");
          ????????????FileInputStream fis = new FileInputStream(f);
          ????????????byte[] ba = new byte[(int)f.length()];
          ????????????fis.read(ba);
          ????????????VTDGen vg = new VTDGen();
          ????????????vg.setDoc(ba);
          ????????????vg.parse(false);
          ????????????VTDNav vn = vg.getNav();
          ????????????if (vn.matchElement("purchaseOrder")){
          ????????????????System.out.println(" orderDate==>"
          ????????????????????+ vn.toString(vn.getAttrVal("orderDate")));
          ????????????????if (vn.toElement(VTDNav.FIRST_CHILD,"item")){
          ????????????????????if (vn.toElement(VTDNav.FIRST_CHILD)){
          ????????????????????????do {
          ????????????????????????????System.out.print( vn.toString(vn.getCurrentIndex()));
          ????????????????????????????????System.out.print("==>");

          ????????????????????????????System.out.println( vn.toString(vn.getText()));
          ????????????????????????} while(vn.toElement(VTDNav.NEXT_SIBLING));
          ????????????????????}
          ????????????????}
          ????????????}
          ????????}
          ????????catch (Exception e){
          ????????????System.out.println("exception occurred ==>"+e);
          ????????}
          ????}
          }



          實現同樣功能的DOM版本的程序:

          import java.io.*;
          import org.w3c.dom.*;
          import org.w3c.*;
          import javax.xml.parsers.*;
          import javax.xml.parsers.DocumentBuilder;
          import javax.xml.parsers.DocumentBuilderFactory;
          import javax.xml.parsers.FactoryConfigurationError;
          import javax.xml.parsers.ParserConfigurationException;
          import org.w3c.dom.*;
          import org.xml.sax.SAXException;

          public class use_dom {
          ????public static void main(String[] args){
          ????????try{
          ????????????DocumentBuilderFactory factory =
          ????????????DocumentBuilderFactory.newInstance();
          ????????????DocumentBuilder parser = factory.newDocumentBuilder();
          ????????????Document d= parser.parse("test.xml");
          ????????????Element root = d.getDocumentElement();
          ????????????if (root.getNodeName().compareTo("purchaseOrder")==0){
          ????????????????System.out.println(" orderDate==> "
          ????????????????????+ root.getAttribute("orderDate"));

          ????????????????Node n = root.getFirstChild();
          ????????????????if (n != null){
          ????????????????????do {
          ????????????????????????if (n.getNodeType() == Node.ELEMENT_NODE
          ????????????????????????????&& n.getNodeName().compareTo("item")==0){
          ????????????????????????????Node n2 = n.getFirstChild();
          ????????????????????????????if (n2!=null){
          ????????????????????????????????do {
          ????????????????????????????????????if (n2.getNodeType()
          ????????????????????????????????????????== Node.ELEMENT_NODE){????
          ????????????????????????????????????????System.out.println(
          ????????????????????????????????????????????n2.getNodeName()
          ????????????????????????????????????????????+ "==>" +
          ????????????????????????????????????????????n2.getFirstChild().getNodeValue()
          ????????????????????????????????????????);
          ????????????????????????????????????}
          ????????????????????????????????}while((n2=n2.getNextSibling())!=null);
          ????????????????????????????}
          ????????????????????????}
          ????????????????????}while ((n=n.getNextSibling()) != null );
          ????????????????}
          ????????????}
          ????????}
          ????????catch (Exception e){
          ????????????System.out.println("exception occurred ==>"+e);
          ????????}????
          ????}
          }



          像以上所展示的那樣,VTD-XML使用基于游標的API來訪問XML層次結構。相比之下,DOM API通過請求對象的引用來達成同樣目標。VTD-XML的項目網站提供更多詳細的技術資料和示例程序。

          VTD-XML的基準測試

          下面,我們來比較一下VTD-XML一些流行的XML解析器的性能和內存占用情況。值得注意的是,多數包含基準測試數據的文章,如Dennis Sosnoski于2002年4月發表在JavaWorld上的“XML Documents on the Run”,都是多年前的文章。自那以后,如摩爾定律所示,更好更快的硬件大量涌現并越來越便宜。同時,XML解析與JVM技術也并未止步不前――在一些關鍵領域做出了改進。

          測試設置
          測試平臺是Sony VAIO筆記本電腦,使用Pentium M 1.7 GHz處理器(2MB L2 cache),512MB DDR2內存。前端總線頻率為400MHz。操作系統為Windows XP Professional Edition with Services pack 2。JVM版本為1.5.0_06。
          對以下XML解析器的最新版本進行了基準測試:
          *Xerces DOM 2.7.1, 帶有及不帶有延遲節點擴展(deferred node expansion)
          *Xerces SAX 2.7.1
          *Piccolo SAX 1.04
          *XPP3 1.1.3.4.O
          *VTD-XML 1.5, 帶有及不帶有緩沖重用

          在測試中我使用了大量不同大小和不同復雜程度的XML文檔。從文檔大小上,我把它們分為三類:小文件(小于10KB);中文件(10KB至1MB);大文件(大于1MB)。
          在全部的性能度量中我都使用了服務器的JVM來獲取最高性能。在這些測試中,基準測試程序首先會多次解析或訪問文檔,使JVM對字節碼進行即時動態優化,之后才取得性能的平均值作為最終結果。為了減少由于磁盤IO導致的時間差別,基準測試程序在測試運行之前已經把XML文件讀入到內存中。

          注意:有興趣的讀者可以從資源下載基準測試程序。

          吞吐量對比解析
          本節在延遲時間和吞吐量上對XML解析性能進行描述。要注意的是VTD-XML與DOM可直接進行比較,而與SAX或Pull直接對比就很不公平,因為它們不在內存中構建任何層次結構。因此SAX和Pull的性能在此只作為額外參考。
          吞吐量

          image
          圖 1. 小文件.
          ????
          image
          圖 2. 中文件.
          ????
          image
          圖 3. 大文件.

          延遲時間對比
          表 1. 小文件
          image

          表 2. 中文件
          image

          表 3. 大文件
          image

          內存占用率對比
          因為SAX和Pull不在內存中構建任何數據結構,所以這項測試只有與DOM的對比才有意義。因此,本節對倍加系數(multiplying factor)進行衡量,該系數為內存占用率與大文件的文件大小之比(內存占用對大文件特別重要)。

          image
          圖 4.

          訪問性能對比
          本節從延遲時間上展示VTD-XML與DOM 的訪問性能。延遲時間是指訪問文檔中每個節點所花的時間。為了遍歷所有節點,DOM依賴于nodeInterator接口,而VTD-XML則調用AutoPilot類的成員方法selectElement(…)與iterate(…)。如所預期的一樣,訪問速度比解析速度要快得多。對VTD-XML,訪問時間開銷在解析時間開銷的15%到30%之間。對DOM,該數字為5%到7%。這并不說明VTD-XML的訪問速度慢于DOM。這完全是因為VTD-XML有著非常快的解析速度。

          表 4. 小文件
          image

          表 5. 中文件
          image

          表 6. 大文件
          image

          結果分析
          在Dennis Sosnoski四年前發表于JavaWorld的文章中,Piccolo是眾多SAX實現中的贏家。現在這得到了改變:最新的Xerces擊敗眾多對手成為性能最好的SAX解析器。測試結果也顯示,與Xerces相比,XPP3也有相當不錯的性能,不比前者相差很多。
          另外,有趣的是,當文件較小時,DOM與SAX的解析性能差距并不像在解析大文件時的相差那么大。在小文件的情況下,DOM的延遲節點擴展導致比使用完全節點擴展要差的解析性能。

          而VTD-XML的出眾性能使它完全勝過其他任何解析器,這使它自成一級。真正的比較只是存在于使用緩沖重用的VTD-XML及不使用緩沖重用的VTD-XML之間。內存占用率上的重大優勢使得VTD-XML可以被用于處理大XML文檔,并且對任意大小的文件都有較好的性能。

          結論

          VTD-XML是一種全新的,下一代的XML解析器。它解決了許多目前困擾DOM和SAX的問題。VTD-XML高性能與低內存占用的結合意味著:首先,DRAM已經相當便宜,如果不是完全沒有空間存放XML文檔,那就沒有多少理由使用SAX;其次,使用VTD-XML使得應用變得更加簡單,更快。它對各種大小的文件的適應性,使得選擇一個合適的XML處理模型變得簡單,而開發人員也不必再在完全不同的DOM和SAX中進行切換了;最后,VTD-XML可以為長久以來對XML的不滿提供一個令人信服的答案。比如,VTD-XML內建了本地XML索引的能力,也許可以永久改變認為XML速度慢的看法。正由于它的性能優勢,VTD-XML應該標志著“10倍速XML”時代的到來。更重要的是,VTD-XML的下一站,只在咫尺之遙,那就是“100倍速XML”。

          資源
          *VTD-XML:http://vtd-xml.sf.net/
          *Apache Axis FAQ:http://ws.apache.org/axis/faq.html#faq1
          *下載基準測試程序:http://sourceforge.net/project/showfiles.php?group_id=110612



          Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=933706

          posted on 2006-08-29 13:20 放水老倌 閱讀(947) 評論(0)  編輯  收藏 所屬分類: XML
          主站蜘蛛池模板: 南郑县| 镇雄县| 灵石县| 卢龙县| 崇左市| 馆陶县| 方山县| 平乡县| 育儿| 乐都县| 武定县| 桃源县| 石城县| 通州区| 德保县| 光泽县| 蒲城县| 莱西市| 德江县| 龙岩市| 郧西县| 台中市| 伊金霍洛旗| 平泉县| 广德县| 色达县| 合阳县| 四子王旗| 嵊州市| 郑州市| 全南县| 云和县| 茌平县| 婺源县| 吉安县| 深州市| 河西区| 察隅县| 竹溪县| 洪洞县| 周至县|