灵魂-放水

为学日益,为道日损。

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 放水老倌 阅读(934) 评论(0)  编辑  收藏 所属分类: XML

只有注册用户登录后才能发表评论。


网站导航: