分享
 
 
 

创建高效的MSXML应用

王朝other·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

创建高效的MSXML应用

code{font-family:"courier new";color:#006}

pre{font-family:"courier new";background-color:#e1e1e1;color:#006}

a {text-decoration:underline}

创建高效的MSXML应用

原作:Ben Berck 2002.03.06

翻译: onestab 2002.08.03

我阅读过几十篇书籍和文章,都是为那些需要用XML做些事情的程序员提供指导的。这些资料对初学XML开发的程序员是有帮助的,并且带有一些短小的例子(都在10KB以下,通常小于1KB)。

在这些例子中用到的技术并不总适用于实际开发,尤其是处理特别巨大的文件时。比如,当你需要处理122MB大小的XML文件,每个文件都源于不同的应用程序时会发生什么?

这就是我的团队在尝试为公司开发基于服务器的XML执行引擎,以及试验一个允许任何人上传文件并将其转换为XML, SVG,HTML等格式的网站时所面临的两难境地。简言之,我们的目的是要能够处理任何东西,从Microsoft Word到Quark文件,哪个都不算小。

显然最先想到的就是增加内存和提高处理器的处理能力。不过这也太容易了些,因为我们想到了大O问题。还记得大学里学过的大O表示法吗?一个算法可以用所占用的处理器周期(时间)和消耗的内存(空间)与其所要处理的元素数量之比来衡量。大O表示法代表了算法固有的适用范围,比如一个时间复杂度为O(n2)或空间复杂度为O(n2)的算法的效率较低,因为它极大地限制了计算机所能处理的问题的规模。

当我们试图用一个支持XML DOM的解析器解析一个很大的XML文件时,就首先遇到了这个大O问题。这种方案是将整个XML文件以树型结构装入内存。装入或存储文件所用的时间为O(n)。初看起来似乎可以接受,然而,除了简单的装入文件,要做的事情还有许多。

我们还要写代码读这个DOM,分析它,让它干活。我们曾经假定这种分析(比如查找某个元序)所花的时间为O(n)。出乎我们的意料,实际所花的时间是我们无法接受的O(n2)。

我们通过分析找出了问题的关键:getItem。这是许多DOM程序员最常用的简单函数。就像检索一个数组一样,这种方法简单而且好用 -- 至少对小的XML文件来说是如此。然而,DOM树实际上更像一个链表,无法随机访问。DOM中这个方法的实现必须要遍历链表。在包含n个元素的链表中循环时,将会有0.5(n2-n)次引用,即O(n2)。从文档中我们很快发现DOM中的另一个函数nextNode也能提供所要的这种功能。我们于是就更改了这行代码,很快就得出了结果(如下表所示)。对于这种大型XML来说,改变一行代码就会显著地提高性能。

10,000 个节点

100,000 个节点

1 百万个节点

getItem( i )

15 秒

~23 秒

> 1 小时 (未完成)

nextNode( )

1 秒

12 秒

~200 秒

服务器产品的开发者都知道,当你想同时处理多个用户和进程时,内存是极其宝贵的资源。只是简单地把getItem改为netNode并不能阻止DOM很快地消耗掉你的服务器内存。

对于大多数的处理任务,没有必要将整个XML文件装入内存。XML开发人员都认为在处理大文件时,像SAX之类的基于事件的解析器是个更好的选择,因为它不须将多个元素同时装入内存。开始处理元素时调用一个函数,干完活后,就弃掉它。元素被SAX解析器丢弃后,所处理的XML文件的哪部分应当保存在内存中(或相反)要由开发者做出决定。

我们很快决定从DOM转到SAX。最终,我们的核心部件之一就能简单地抽取大型XML文件并存到另一个文件,不需要保存任何状态信息。但是,我们追求的是O(1)的空间性能,这也是任何精巧的服务器应用程序所渴求的。

我们采用MSXML3.0所带的SAX来处理文档。微软的MXXMLWriter设计了一个ContentHandler,它可以接受与SAX同样的事件入口参数。在微软给出的示例中,整个过程是互相关联的,这就意味着你可以高效地将XML文件复制到MXXMLWriter。我们简单地增加了些代码,将这种复制操作仅限定于SAX解析过程中所遇到的元素子集。不过,现在它还不在磁盘上,在将其送回到磁盘之前,UTF-8编码出了些小问题。

还有另一个问题。MXXMLWriter将它的所有输出都放在一个名为output的字符串属性中。这就是我们在开发服务器应用程序时所遇到的另一个大O问题。MXXMLWriter将收集到的子文件都放在内存中,当我们准备将它存回磁盘时,必须要申请一块几乎同样大小的内存进行Unicode到UTF-8的转换。因为子文件的大小随着原来的XML文件的大小呈线性增加,我们的O(1)空间算法降为O(n),效果不好。

微软关于IMXWriter的文档中的output属性的说明部分给我们带来了希望:“你可以将这个属性设置为任何IStream接口的实现,结果文件将被写入所提供的IStream.”

听起来令人鼓舞,但是由于缺少示例代码和有关IStream接口的COM详细资料却令我们很为难。最终,我们发现,一旦你用一个恰当设计的IStream钩起了MXXMLWriter,程序的其余部分是不变的。每当MXXMLWriter积累起4,096个Unicode字符(占用8 KB内存),就会调用IStream的Write方法,将缓冲区的内容转换为UTF-8(另外占用3.3 KB)并写入文件。不管文件或子文件有多大,这种设计一次消耗的内存不超过几十KB。这就是所谓的O(1)空间性能,意味着现在你可以到忙碌的服务器上的其它地方去寻找瓶颈了。

我准备了实现IStream的IFileStream类的代码样本,以及将缓冲区内容从Unicode转换为UTF-8的代码,xml_article.cpp

xml_article.h

如果你想看看我们正在使用的XML执行服务器,请访问http://createxml.com

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有