作者:Jimmy Zhang;rainy14f(作者的blog:http://shaofan.blogjava.net/)
概要
做為下一代WEB應(yīng)用的推動(dòng)性技術(shù),XML相當(dāng)簡單,易學(xué)易用。然而,當(dāng)前的XML處理技術(shù)卻非如此。Document Object Model和Simple API for XML都比較慢,低效,且不易于使用。VTD-XML,作為下一代的XML處理模型,提供超越DOM和SAX的廣泛用途和更佳選擇,不僅可以簡化XML編程,也使選擇XML處理模型更加容易。這篇文章通過最近的基準(zhǔn)測試數(shù)據(jù)和示例程序來突顯它的關(guān)鍵性的技術(shù)優(yōu)勢,顯示出VTD-XML將可能解決長期以來困擾企業(yè)架構(gòu)的,在DOM和SAX之間進(jìn)行抉擇的問題。
自從誕生以來的八年里,XML作為一個(gè)開放,半結(jié)構(gòu)化的數(shù)據(jù)格式和WEB應(yīng)用的數(shù)據(jù)交換工具,已取得了長足進(jìn)步。由于它的簡易性和良好的可讀性,XML受到開發(fā)人員的熱烈歡迎,并且已經(jīng)成為了企業(yè)架構(gòu)不可分割的一部分。
雖然很難說清XML到底有多少種不同的應(yīng)用,但至少有一點(diǎn)是肯定的:XML解析處理已成為各種工作的先決任務(wù)。實(shí)際上,決定使用哪種解析器也經(jīng)常是企業(yè)開發(fā)者在項(xiàng)目中必須首先解決的問題之一。長久以來,這其實(shí)就是在兩種 XML處理模型之間做出選擇:Document Object Model (DOM) 和 Simple API for XML (SAX)。
粗看之下,DOM和SAX各自的優(yōu)缺點(diǎn)剛好形成互補(bǔ)。DOM使用內(nèi)存保存對象結(jié)構(gòu);而SAX則基于事件并且不使用內(nèi)存來存儲任何數(shù)據(jù)。因此,DOM比較適合文檔較小而數(shù)據(jù)訪問模式復(fù)雜的情況,相反情況下,則使用SAX。
然而事實(shí)卻并不這么單純。很多情況下,開發(fā)者不情愿使用復(fù)雜的SAX,但又不得不用,因?yàn)闆]有其他選擇。此外,即使XML文件的大小只是稍微大于幾百K,DOM的內(nèi)存開銷和性能遲滯也會成為棘手的障礙,使得程序無法達(dá)到項(xiàng)目所要求的最低性能目標(biāo)。
那么是否SAX的性能真得好得多?實(shí)際上,SAX所吹噓的解析性能――通常比DOM快幾倍――常常是不現(xiàn)實(shí)的。事實(shí)顯示,SAX笨拙的,只能往前的解析不僅在使用時(shí)相當(dāng)不便,而且當(dāng)文檔結(jié)構(gòu)稍微復(fù)雜時(shí),也會遇到性能問題。如果開發(fā)人員不想多次掃描文檔,那么就需要對文檔進(jìn)行緩沖,或構(gòu)建自己的對象模型。
不管使用哪種方法,性能都會成為問題,正如Apache Axis所證明的那樣。在Axis的FAQ頁面,它聲稱使用了SAX來構(gòu)建高性能的實(shí)現(xiàn),但它仍然使用了他們自己的和DOM非常相像的對象模型。但與它的前任 (Apache SOAP) 相比,這種做法并沒有帶來明顯的性能提升。而且,SAX無法處理XPath,一般來說也無法驅(qū)動(dòng)XSLT (Extensible Stylesheet Language Transformation) 的處理。因此,SAX仍然無法真正解決XML處理中的問題。
為了尋找一個(gè)更易用的SAX的取代方案,越來越多的開發(fā)人員開使轉(zhuǎn)向StAX (Streaming API for XML)。與SAX相比,StAX使用從XML文件中提取標(biāo)記的方法,而不是回調(diào)。這種方案顯著地改善了可用性,但一個(gè)基本的問題仍然存在――StAX的只能往前的解析對于程序員依然不便,而且存在隱藏的性能損失。
底線是:任何想得到廣泛應(yīng)用的XML處理模型,必需能夠完整體現(xiàn)XML的層次結(jié)構(gòu)。這是因?yàn)椋琗ML是被設(shè)計(jì)為在WEB上傳輸復(fù)雜數(shù)據(jù)的,因此完整展現(xiàn)它的結(jié)構(gòu)信息也是它的任務(wù)之一。
VTD-XML改變了游戲
假設(shè)我們要從頭開始一個(gè)XML處理過程,并克服上面提到的DOM和SAX的種種缺點(diǎn),那么這個(gè)新的模型應(yīng)該具有以下屬性:
* 隨機(jī)訪問能力:處理模型應(yīng)該允許開發(fā)人員方便訪問文檔的某種層次結(jié)構(gòu),比如,使用XPath,或手動(dòng)。
* 高性能:性能上與DOM及SAX相比,應(yīng)有顯著提高,而且這個(gè)“性能”應(yīng)該是真實(shí)的,就是說,應(yīng)該把建立文檔層次結(jié)構(gòu)的時(shí)間也算上。
* 低內(nèi)存占用率:要使該模型能夠被廣泛應(yīng)用于各種場景,不管文件的大小,那它就必須能夠以最低的內(nèi)存消耗來表現(xiàn)XML的結(jié)構(gòu)。
VTD-XML就是一個(gè)實(shí)現(xiàn)了這些目標(biāo)的下一代的開源XML處理模型。它相比于DOM和SAX有著本質(zhì)和全面的改進(jìn)。VTD-XML的一個(gè)關(guān)鍵優(yōu)化是非提取符號(non-extractive tokenization)。在其內(nèi)部,VTD-XML在內(nèi)存中保存完整及未解碼的XML消息,并使用一個(gè)二進(jìn)制編碼規(guī)范來唯一地表示每個(gè)符號。這種規(guī)范被稱為Virtual Token Descriptor(虛擬符號描述符)。每個(gè)VTD記錄都是一個(gè)64字節(jié)的整數(shù),它對XML中符號的長度,起始偏移量,類型,嵌套深度進(jìn)行了編碼。
再簡單地介紹一下VTD-XML的歷史,也許你會感興趣:最初這個(gè)概念是被用來在特定硬件設(shè)備上使用,以使這些硬件(如路由器,交換機(jī))可以高速處理XML,比如FPGA,ASIC。此后,VTD-XML項(xiàng)目組決定使它開源,并于2004年五月發(fā)布了VTD-XML的最初版本,0.5版,用JAVA實(shí)現(xiàn)。從那時(shí)起。VTD-XML經(jīng)歷了多次改進(jìn)并越來越成熟。在0.8版本中,C語言版本的VTD-XML與JAVA版同時(shí)發(fā)布。在1.0版中引入了對XPath的內(nèi)建支持,于2005年10月發(fā)布。最新的版本是1.5版,它的解析引擎被重新編寫以實(shí)現(xiàn)更強(qiáng)的模塊化和更高的性能。
同樣,在這個(gè)版本中還出現(xiàn)了一個(gè)新的特性,叫作緩沖重用。它的基本概念是,當(dāng)XML應(yīng)用需要通過網(wǎng)絡(luò)連接來反復(fù)地讀入XML文檔時(shí),該應(yīng)用會重用在第一次處理中分配的內(nèi)存緩沖。換句話說,即一次分配,多次使用。就VTD-XML來講,這個(gè)特性完全消除了在處理XML過程中建立對象和垃圾回收的開銷(在DOM和SAX中占用50%至80%的開銷)。在該項(xiàng)目的網(wǎng)站上,提供有最新的軟件下載和深層技術(shù)說明。
一個(gè)簡短例子
為了使你更好地了解VTD-XML編程的風(fēng)格,本文首先對用VTD-XML和DOM解析和訪問一個(gè)簡單的XML文件進(jìn)行對比。該文件名為test.xml,內(nèi)容如下:
<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);
????????}
????}
}
實(shí)現(xiàn)同樣功能的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使用基于游標(biāo)的API來訪問XML層次結(jié)構(gòu)。相比之下,DOM API通過請求對象的引用來達(dá)成同樣目標(biāo)。VTD-XML的項(xiàng)目網(wǎng)站提供更多詳細(xì)的技術(shù)資料和示例程序。
VTD-XML的基準(zhǔn)測試
下面,我們來比較一下VTD-XML一些流行的XML解析器的性能和內(nèi)存占用情況。值得注意的是,多數(shù)包含基準(zhǔn)測試數(shù)據(jù)的文章,如Dennis Sosnoski于2002年4月發(fā)表在JavaWorld上的“XML Documents on the Run”,都是多年前的文章。自那以后,如摩爾定律所示,更好更快的硬件大量涌現(xiàn)并越來越便宜。同時(shí),XML解析與JVM技術(shù)也并未止步不前――在一些關(guān)鍵領(lǐng)域做出了改進(jìn)。
測試設(shè)置
測試平臺是Sony VAIO筆記本電腦,使用Pentium M 1.7 GHz處理器(2MB L2 cache),512MB DDR2內(nèi)存。前端總線頻率為400MHz。操作系統(tǒng)為Windows XP Professional Edition with Services pack 2。JVM版本為1.5.0_06。
對以下XML解析器的最新版本進(jìn)行了基準(zhǔn)測試:
*Xerces DOM 2.7.1, 帶有及不帶有延遲節(jié)點(diǎn)擴(kuò)展(deferred node expansion)
*Xerces SAX 2.7.1
*Piccolo SAX 1.04
*XPP3 1.1.3.4.O
*VTD-XML 1.5, 帶有及不帶有緩沖重用
在測試中我使用了大量不同大小和不同復(fù)雜程度的XML文檔。從文檔大小上,我把它們分為三類:小文件(小于10KB);中文件(10KB至1MB);大文件(大于1MB)。
在全部的性能度量中我都使用了服務(wù)器的JVM來獲取最高性能。在這些測試中,基準(zhǔn)測試程序首先會多次解析或訪問文檔,使JVM對字節(jié)碼進(jìn)行即時(shí)動(dòng)態(tài)優(yōu)化,之后才取得性能的平均值作為最終結(jié)果。為了減少由于磁盤IO導(dǎo)致的時(shí)間差別,基準(zhǔn)測試程序在測試運(yùn)行之前已經(jīng)把XML文件讀入到內(nèi)存中。
注意:有興趣的讀者可以從資源下載基準(zhǔn)測試程序。
吞吐量對比解析
本節(jié)在延遲時(shí)間和吞吐量上對XML解析性能進(jìn)行描述。要注意的是VTD-XML與DOM可直接進(jìn)行比較,而與SAX或Pull直接對比就很不公平,因?yàn)樗鼈儾辉趦?nèi)存中構(gòu)建任何層次結(jié)構(gòu)。因此SAX和Pull的性能在此只作為額外參考。
吞吐量

圖 1. 小文件.
????

圖 2. 中文件.
????

圖 3. 大文件.
延遲時(shí)間對比
表 1. 小文件

表 2. 中文件

表 3. 大文件

內(nèi)存占用率對比
因?yàn)镾AX和Pull不在內(nèi)存中構(gòu)建任何數(shù)據(jù)結(jié)構(gòu),所以這項(xiàng)測試只有與DOM的對比才有意義。因此,本節(jié)對倍加系數(shù)(multiplying factor)進(jìn)行衡量,該系數(shù)為內(nèi)存占用率與大文件的文件大小之比(內(nèi)存占用對大文件特別重要)。

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

表 5. 中文件

表 6. 大文件

結(jié)果分析
在Dennis Sosnoski四年前發(fā)表于JavaWorld的文章中,Piccolo是眾多SAX實(shí)現(xiàn)中的贏家。現(xiàn)在這得到了改變:最新的Xerces擊敗眾多對手成為性能最好的SAX解析器。測試結(jié)果也顯示,與Xerces相比,XPP3也有相當(dāng)不錯(cuò)的性能,不比前者相差很多。
另外,有趣的是,當(dāng)文件較小時(shí),DOM與SAX的解析性能差距并不像在解析大文件時(shí)的相差那么大。在小文件的情況下,DOM的延遲節(jié)點(diǎn)擴(kuò)展導(dǎo)致比使用完全節(jié)點(diǎn)擴(kuò)展要差的解析性能。
而VTD-XML的出眾性能使它完全勝過其他任何解析器,這使它自成一級。真正的比較只是存在于使用緩沖重用的VTD-XML及不使用緩沖重用的VTD-XML之間。內(nèi)存占用率上的重大優(yōu)勢使得VTD-XML可以被用于處理大XML文檔,并且對任意大小的文件都有較好的性能。
結(jié)論
VTD-XML是一種全新的,下一代的XML解析器。它解決了許多目前困擾DOM和SAX的問題。VTD-XML高性能與低內(nèi)存占用的結(jié)合意味著:首先,DRAM已經(jīng)相當(dāng)便宜,如果不是完全沒有空間存放XML文檔,那就沒有多少理由使用SAX;其次,使用VTD-XML使得應(yīng)用變得更加簡單,更快。它對各種大小的文件的適應(yīng)性,使得選擇一個(gè)合適的XML處理模型變得簡單,而開發(fā)人員也不必再在完全不同的DOM和SAX中進(jìn)行切換了;最后,VTD-XML可以為長久以來對XML的不滿提供一個(gè)令人信服的答案。比如,VTD-XML內(nèi)建了本地XML索引的能力,也許可以永久改變認(rèn)為XML速度慢的看法。正由于它的性能優(yōu)勢,VTD-XML應(yīng)該標(biāo)志著“10倍速XML”時(shí)代的到來。更重要的是,VTD-XML的下一站,只在咫尺之遙,那就是“100倍速XML”。
資源
*VTD-XML:http://vtd-xml.sf.net/
*Apache Axis FAQ:http://ws.apache.org/axis/faq.html#faq1
*下載基準(zhǔn)測試程序:http://sourceforge.net/project/showfiles.php?group_id=110612
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=933706