前两天有朋友问,我的SlimXml有没有和RapidXml对比过效率?我是第一次听说这个库,更不用说对比效率了,于是上他们网站看了下。
好家伙,居然号称比TinyXml快30~60倍,而且是Boost.PropertyTree的默认xml解析器。
于是有点好奇,因为以前也没有特别关心过SlimXml的效率。
于是分别下载了TinyXml-2.6.1和RapidXml-1.13,迅速用vc8建立了两个测试工程,在系统中搜”*.xml”,找到了一个比较合适的测试文件。它足够大(1.5M),utf-8编码并且包含中/英文,有一定层次深度,大约3.3万行。测试文件可以从这里下载
测试对象是三个库从内存字符串解析xml的函数,这样能排除从硬盘上读文件这种不稳定因素的干扰,而且RapidXml貌似只支持从内存里解析
- slim::XmlDocument::loadFromMemory()
- TiXmlDocument::Parse()
- rapidxml::xml_document<char>::parse<flag>()
要说明的是,RapidXml的这个parse是一个模板函数,必须给一个flag的参数,我测试的时候给的是默认的0
测试结果,解析这个3.3万行,1.5M大小的xml,三个库分别花了
- SlimXml: 13ms
- TinyXml: 54ms
- RapidXml: 4ms!
结论是,RapidXml果然很强悍,居然效率是SlimXml的3倍多。但是并没有如作者所说比TinyXml快30~60倍,只有不到15倍。据说对比用的是一个约50k大小的xml文件,可惜并没有提供下载,不然可以验证一下。
比较欣慰的是,在我并没有很关注效率的情况下,SlimXml仍然比TinyXml快3倍。SlimXml走的是简单小巧路线,源代码只有32k,而TinyXml和RapidXml的源码分别是147k和141k,有这样的效率可以满意了。在我有很多空闲以前,估计我也不会再去优化它,因为这个库主要还是针对几十上百行的小文件,解析特别大的xml不在我考虑的范围之内。
以下是RapidXml提供的常见xml库效率对照表,其中还很牛鼻地提供了和strlen()函数的效率对比
我估计RapidXml速度快的主要原因是对memory pool的使用,毕竟在解析过程中需要创建大量的string,可以想象用memory pool和直接走默认的new很容易产生超过一个数量级的效率差异。
——————————————————————————————————————————————————-
后记:后来还是忍不住用最小代价做了一版优化,基本思路是不再为每个节点/属性复制字符串,而是直接将输入的原始buffer截断成小的字符串,节点/属性对象上只保存指针。这样省去内存申请和字符串拷贝的开销,不但提高了效率,理论上也能节省一定的内存,因为向操作系统申请的内存尺寸越小,“得房率”也越低……
优化之后,原先需要22ms解析的测试文件,现在只需要约13ms。
之后又尝试了一个最土的allocator–也就是只考虑分配不考虑释放,大约能把开销降低到8ms,仍然比RapidXml慢一倍,看来rapid这个名字的确不是盖的。考虑到这个allocator实用价值不高,代码没有commit