以文本方式查看主题 - 中文XML论坛 - 专业的XML技术讨论区 (http://bbs.xml.org.cn/index.asp) -- 『 DTD/XML Schema 』 (http://bbs.xml.org.cn/list.asp?boardid=23) ---- Java 中的 XML:文档模型,第一部分:性能 (http://bbs.xml.org.cn/dispbbs.asp?boardid=23&rootid=&id=12031) |
-- 作者:anchen0617 -- 发布时间:11/13/2004 2:45:00 PM -- Java 中的 XML:文档模型,第一部分:性能 在本文中,Java 顾问 Dennis Sosnoski 比较几个 Java 文档模型的性能和功能。当选择模型时,无法做到每次都权衡得很清楚,如果以后改变主意,则需要大量编码来进行切换。作者将性能结果放入特性集合的上下文中并遵循标准,对所要求的正确选择给出了一些建议。本文包含用于这组测试的几张图表和源代码。 使用内存中 XML 文档的 Java 开发者可以选择使用标准 DOM 表示或几个 Java 特定模型中的任何一个。该灵活性已经帮助将 Java 建立成 XML 工作的出色平台。但是,由于不同模型数量的增加,已经更加难以确定如何比较模型的功能、性能和易用性。 关于使用“Java 中的 XML”系列中的第一篇文章研究了 Java 中一些领先的 XML 文档模型的特性和性能。它包括一组性能测试的结果(带有可下载的测试代码,请参阅参考资料)。在系列中的第二篇文章将通过比较为实现同样任务所使用的不同模型的样本代码来研究易用性问题。 文档模型 仅为说明本文中所使用的术语: 解析器是指解释 XML 文本文档结构的程序
某些 XML 应用程序根本不需要使用文档模型。如果应用程序可以通过文档的一次遍历搜集它需要的信息,则可能直接使用解析器。该方法可能需要增加一些工作量,但是它的性能总是优于在内存中构建文档表示。 DOM DOM 定义充分利用了 XML 文档不同组件的接口和继承性。这为开发者带来了将公共接口用于几个不同类型组件的优势,但是同时增加了 API 的复杂性。因为 DOM 是与语言无关的,所以接口不需要利用公共 Java 组件,例如,Collections 类。 本文涉及两个 DOM 实现:Crimson 和 Xerces Java。Crimson 是基于 Sun Project X 解析器的 Apache 项目。它合并一个包含 DTD 支持的完整验证解析器。可以通过 SAX2 接口访问该解析器,并且 DOM 实现可以与其它 SAX2 解析器一起工作。Crimson 是在 Apache 许可证下发布的开放源码。用于性能比较的版本是 Crimson 1.1.1(jar 文件大小是 0.2MB),它包含有用于从文本文件的 DOM 构建的 SAX2 解析器。 另一个测试的 DOM 实现,即 Xerces Java 是另一个 Apache 项目。初始时,Xerces 基于 IBM Java 解析器(通常称为 XML4J)。(当前还处于早期 beta 测试版的重新开发的 Xerces Java 2 将最终继承它。当前版本有时称为 Xerces Java 1。)如同使用 Crimson 一样,可以通过 SAX2 接口和 DOM 来访问 Xerces 解析器。然而,Xerces 不提供将 Xerces DOM 与不同的 SAX2 解析器一起使用的任何方法。Xerces Java 包含对 DTD 和 XML Schema 的验证支持(仅带有对 Schema 支持的最小限制)。 Xerces Java 还支持 DOM 的延迟节点扩展方式(请参考本文中的延迟 Xerces 或 Xerces def.),其中文档组件初始时是以压缩格式表示的,仅当使用时才将它扩展成完整的 DOM 表示。这种方式的用意是允许更快的解析并降低内存的使用,尤其对于那些可能仅使用部分输入文档的应用程序。与 Crimson 类似,Xerces 是在 Apache 许可证下发布的开放源码。用于性能比较的版本是 Xerces 1.4.2(jar 文件大小是 1.8MB)。 JDOM JDOM 与 DOM 主要有两方面不同。首先,JDOM 仅使用具体类而不使用接口。这在某些方面简化了 API,但是也限制了灵活性。第二,API 大量使用了 Collections 类,简化了那些已经熟悉这些类的 Java 开发者的使用。 JDOM 文档声明其目的是“使用 20%(或更少)的精力解决 80%(或更多)Java/XML 问题”(根据学习曲线假定为 20%)。JDOM 对于大多数 Java/XML 应用程序来说当然是有用的,并且大多数开发者发现 API 比 DOM 容易理解得多。JDOM 还包括对程序行为的相当广泛检查以防止用户做任何在 XML 中无意义的事。然而,它仍需要您充分理解 XML 以便做一些超出基本的工作(或者甚至理解某些情况下的错误)。这也许是比学习 DOM 或 JDOM 接口都更有意义的工作。 JDOM 自身不包含解析器。它通常使用 SAX2 解析器来解析和验证输入 XML 文档(尽管它还可以将以前构造的 DOM 表示作为输入)。它包含一些转换器以将 JDOM 表示输出成 SAX2 事件流、DOM 模型或 XML 文本文档。JDOM 是在 Apache 许可证变体下发布的开放源码。用于性能比较的版本是 JDOM Beta 0.7(jar 文件大小是 0.1MB)它带有用于从文本文件构建 JDOM 表示的 Crimson SAX2 解析器。 dom4j 为支持所有这些功能,dom4j 使用接口和抽象基本类方法。dom4j 大量使用了 API 中的 Collections 类,但是在许多情况下,它还提供一些替代方法以允许更好的性能或更直接的编码方法。直接好处是,虽然 dom4j 付出了更复杂的 API 的代价,但是它提供了比 JDOM 大得多的灵活性。 在添加灵活性、XPath 集成和对大文档处理的目标时,dom4j 的目标与 JDOM 是一样的:针对 Java 开发者的易用性和直观操作。它还致力于成为比 JDOM 更完整的解决方案,实现在本质上处理所有 Java/XML 问题的目标。在完成该目标时,它比 JDOM 更少强调防止不正确的应用程序行为。 dom4j 使用相同方法作为 JDOM 输出,这依靠 SAX2 解析器输入处理,依靠转换器将输出处理成 SAX2 事件流、DOM 模型或 XML 文本文档。dom4j 是在 BSD 样式许可证下发布的开放源码,该许可证本质上等价于 Apache 样式许可证。用于性能比较的版本是 dom4j 0.9(jar 文件大小是 0.4MB),带有用于从文本文件构建表示的受绑定 AElfred SAX2 解析器(由于 SAX2 选项设置,测试文件之一无法由 dom4j 使用用于 JDOM 测试的同一 Crimson SAX2 解析器来处理)。 Electric XML 虽然 EXML 通过使用抽象的基本类方法取得了某些相同效果,但它在避免使用接口方面使用与 JDOM 类似的方法(主要区别是接口为扩展实现提供了更大的灵活性)。它与 JDOM 的不同之处还在于避免使用 Collections 类。该组合为其提供了非常简单的 API,在许多方面类似于带有附加 XPath 操作的 DOM API 简化版本。 仅当空白与非空白文本内容邻近时,EXML 才在文档中保留空白,这就将 EXML 限制成 XML 文档的一个子集。标准 XML 需要在读取文档时保留该空白,除非对文档 DTD 可以确认有无空白无关紧要。对于事先已经知道空白无关紧要的许多 XML 应用程序来说,EXML 方法工作得很好,但是它防止对于期望保留空白的文档(例如,生成由浏览器显示或查看的文档的应用程序)使用 EXML。(有关作者对于该主题的谦虚建议,请参阅副栏使用空白的目的。) 这种空白的删除会对性能比较产生误导效果 — 许多类型的测试范围与文档中的组件个数成比例,并且由 EXML 删除的每个空白序列都是其它模型中的组件。EXML 包含在本文显示的结果中,但是解释性能差异时请记住这种影响。 EXML 使用集成的解析器依据文本文档构建文档表示。除了通过文本方式外,它不提供从 DOM(或 SAX2)转换或转换成 SAX2(或 DOM)事件流的任何方式。EXML 是由 Mind Electric 在禁止将它嵌入某些类型的应用程序或库的受限许可证下发布的开放源码。用于性能比较的版本是 Electric XML 2.2(jar 文件大小是 0.05MB)。 XML Pull Parser XPP 几乎独占地使用接口,但是它仅使用所有类中的一小部分。和 EXML 一样,XPP 避免使用 API 中的 Collections 类。总的来说,它是本文中最简单的文档模型 API。 将 XPP 限制成 XML 文档子集的局限性是它不支持文档中的实体、注释或处理指示信息。XPP 创建仅包含元素、属性(包括“名称空间”)和内容文本的文档结构。这对于某些类型的应用程序来说是一种非常严格的限制。但是通常它对性能的影响比 EXML 空白处理对性能的影响小。在本文中我仅使用了一个与 XPP 不兼容的测试文件,并且在带有注释的图表中显示了 XPP 结果,该注释不包含该文件。 XPP 中的拉回解析器支持(本文中称为 XPP 拉回)通过将解析实际上推迟到访问文档的一个组件时才进行,然后按照构造那个组件的需要对文档进行解析。该技术想实现允许非常快速的文档显示或分类应用,尤其在需要转发或除去(而不是对文档进行完全解析和处理)文档时。该方法的使用是可选的,如果以非拉回型方式使用 XPP,它对整个文档进行解析并且同时地构建完整的表示。 与 EXML 一样,XPP 使用依据文本文档构建文档表示的集成语法解析器,并且除了通过文本方式外,它不提供从 DOM(或 SAX2)转换或转换成 SAX2(或 DOM)事件流的任何方式。XPP 是具有 Apache 样式许可证的开放源代码。用于性能比较的版本是 PullParser 2.0.1 Beta 8(jar 文件大小是 0.04MB)。 测试详细信息 文档模型中的两种(XPP 和 EXML)支持直接将文档输入成“字符串”或字符数组。该类型直接输入不能代表实际应用程序,因此我在这些测试中避免使用它。对于输入和输出,我使用 Java 流封装字节以消除 I/O 对性能的影响,而保留了用于 XML 文档输入和输出的应用程序在典型情况下使用的语言接口。 much_ado.xml,标记成 XML 的莎士比亚戏剧。没有属性并且是相当简单的结构(202K 字节)。 除了非常小的 soap1.xml 文档之外,所有评测时间都是指文档的每次特定测试所经历的时间。在 soap1.xml 的情况下,评测的时间是 49 个连续的文档测试(总数为 20K 字节文本的足够副本数)。 测试框架在一个文档上运行一个特定的测试多次(这里显示运行了 10 次),依此跟踪该测试的最短时间和平均时间,然后继续同一文档上的下一个测试。完成对一个文档的全部测试序列后,它对下一个文档重复该过程。为防止文档模型之间的交互,在执行每个测试框架时仅测试一个模型。 HotSpot 以及类似于动态优化 JVM 的计时基准程序是出了名的棘手的;测试序列中的小变化经常导致计时结果发生很大变化。我已经发现对于执行特定代码段的平均时间时,确实如此;最短时间比较一致,正是我在这些结果中列出的值。可以参阅第一次测试(文档构建时间)的平均和最短时间的比较。 文档构建时间 图 1. 文档构建时间 XPP 的作者在一个电子邮件的讨论中指出,在实际应用程序中,可以合用拉回解析器实例以重新使用。如果这样做的话,soap1.xml 文件的开销将明显降到忽略不计程度。对于更大的文件,甚至不需要合用,拉回解析器创建开销也可以变得忽略不计。 在本测试中,XPP(带有完整解析),带有延迟节点创建的 Xerces 和 dom4j 都显示整体上的同等性能。延迟的 Xerces 对于较大的文档尤其出色,但是对于较小的文档的开销较高 — 甚至比常规 Xerces DOM 高很多。在第一次使用文档的一部分时,延迟节点创建方法的开销也较高,这会降低快速解析的优势。 对于较小的 soap1.xml 文件,所有格式(SAX2 解析、常规 DOM 和延迟 DOM)的 Xerces 的显得开销较高。对于该文件 XPP(完全解析)尤其出色,对于 soap1.xml,EXML 甚至超过基于 SAX2 的模型。虽然 EXML 具有废弃单独的空白内容的优势,但是总体上,它是本测试中最差的。 文档遍历时间 图 2. 文档遍历时间 使用 XPP 拉回时,直到访问文档表示时才真正发生对文档文本的解析。这导致第一次遍历文档表示时的开销非常大(表中未显示)。如果以后访问整个文档表示,则当使用拉回解析方法时,XPP 显示性能的净损失。对于拉回解析器来说,前两个测试所需的总时间比使用 XPP 的常规解析长(长 20% 到 100%,这取决于文档)。但是,当还未完全访问正在进行解析的文档时,拉回解析器方法仍然具有可观的性能优势。 带有延迟节点创建的 Xerces 显示了相似的行为,第一次访问文档表示时导致性能下降(图中未显示)。但是,在 Xerces 情况下,节点创建开销大约与解析期间常规 DOM 创建的性能差值相同。对于较大的文档来说,用 Xerces 延迟的前两次测试所需的总时间大致与使用带常规 DOM 构建的 Xerces 所用的时间相同。如果在非常大的文档(可能 10KB 或更大)上使用 Xerces,则延迟的节点创建似乎是一个好选择。 文档修改时间 图 3. 文档修改时间 在修改性能方面,XPP 仅次于 EXML,并且与 EXML 不同,XPP 测试包含删除。Xerces DOM 和 dom4j 接近地处于中间位置,JDOM 和 Crimson DOM 模型的性能仍是最差。 文本生成时间 图 4. 文本生成时间 许多模型提供了控制文本输出格式的选项,并且一些选项似乎影响文本生成时间。这个测试只使用每个模型的最基本的输出格式,因此结果只显示缺省性能而不显示最好的可能性能。 文档内存大小 图 5. 文档内存大小 除了 XPP 拉回(直到访问它时才真正构建文档表示)之外,与一些计时测试中显示的差别相比,内存大小测试中模型之间的差别相对较小。延迟的 Xerces 具有最紧凑的表示(当第一次访问表示时将它扩展成基本 Xerces 大小),紧接着是 dom4j。虽然 EXML 废弃包含在其它模型中的空白内容,但是它仍具有最不紧凑的表示。 因为即使最紧凑的模型也要占用大约原始文档文本大小(以字节计)四倍的空间,所以对于大文档来说,所有模型似乎都需要太多的内存。通过提供使用部分文档表示的方法,XPP 拉回和 dom4j 为非常大的文档提供了最好的支持。XPP 拉回通过仅构建实际被访问的表示部分完成该任务,而 dom4j 包含对基于事件处理的支持,使得一次只构建或处理文档的一部分。 Java 序列化 图 6. 序列化输出时间 如果将文档输出成文本然后进行解析以重新构建文档,而不是使用 Java 序列化,则所有性能 — 时间和大小 — 都会好得多。这里的问题是作为大量唯一的小对象的 XML 文档表示的结构。Java 序列化无法有效处理这种类型的结构,这导致时间和输出大小的开销都很高。 可以设计比文本表示小且比文本输入和输出快的文档序列化格式,但是只能通过绕过 Java 序列化来完成。(我有一个项目实现 XML 文档的这种定制的序列化,在我公司的 Web 站点上可以找到其开放源码,请参阅参考资料。) 结束语 在大多数方面,XPP 性能处于领先地位。尽管 XPP 是一种新模型,但是对于不需要验证、实体、处理指示信息或注释的中间件类型应用程序来说,它是非常好的选择。它尤其适用于作为浏览器小应用程序或在内存受限的环境下运行的应用程序。 虽然 dom4j 没有与 XPP 同等的速度,但是,它确实提供了具备更标准化的优越性能和功能更全的实现,包括对 SAX2、DOM 甚至 XPath 的内置支持。虽然 Xerces DOM(带有延迟的节点创建)对于小文件和 Java 序列化性能不佳,但是在大多数评测时仍然出色。对于常规 XML 处理,dom4j 和 Xerces DOM 都是很好的选择,对它们的选择取决于您认为是特定于 Java 的特性更重要还是跨语言的兼容性更重要。 JDOM 和 Crimson DOM 在性能测试时一直表现不佳。在小文档情况下还值得考虑使用 Crimson DOM,而 Xerces 表现很差。虽然 JDOM 的开发者已经说明他们期望在正式发行版前专注性能问题,但是从性能观点来看,它确实没有值得推荐之处。然而,如果不进行 API 的重新构建,JDOM 可能难以达到与其它模型匹配的性能。 使用空白的目的 支持修剪输入上这种类型空白的选项将有助于提高带有可忽略的空白的应用程序的所有文档模型的性能(除了 EXML 之外)。只要修剪是一个选项,它就不会影响需要完全保留空白的应用程序。解析器级别的支持将更好,因为解析器必须逐一处理输入字符。总之,这种类型的选项将非常有助于许多 XML 应用程序。 虽然 dom4j 性能最好,但是,当前没有一种模型能为 Java 序列化提供良好性能。如果需要在程序之间传递文档,通常的最佳选择是将文档写成文本然后进行解析以重新构建表示。将来,定制序列化格式可能提供一个更好的选择。 后续内容... 在后续文章中将集中研究可用性,其中我将比较用于完成这些不同模型中相同操作的样本代码。请检查本比较的第二部分。当您等待时,可以通过下面的论坛中的链接提出您对本文的评论和问题与大家共享。
|
W 3 C h i n a ( since 2003 ) 旗 下 站 点 苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》 |
5,671.875ms |