锁定老帖子 主题:比Velocity快10倍的模板引擎
该帖已经被评为精华帖
|
|||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
作者 | 正文 | ||||||||||||||||||||||||||||||||||||
发表时间:2011-09-13
最后修改:2012-02-24
http://www.iteye.com/news/3381,后来功能越来越多,性能却越来越差,在金大为发给我性能对比结果后,看到惨不忍睹的差距,就打算抛弃原设计进行重写,但因工作忙,就搁置了,最近看温少发了几个EL和JSON的解析器,有点手痒,就抽了个周未,拿出来再改了改,主要将模板改成了字节码编译,并简化了语法及缩小使用范围,只针对HTML场景使用,并将名称改成了HTTL,名字含义是把HTML中的M(Marker)改成了T(Template),放在GoogleCode上:http://code.google.com/p/httl,性能和Java硬编码输出模板内容差不多,比Velocity/FreeMarker等快10倍左右。
在07年的时候,写过一个模板引擎,当时叫CommonTemplate,以前JavaEye有个开源系列介绍:
语法方面的区别: 发现基于文本指令的,基于HTML标签的,基于HTML注释的,都有不少模板引擎实现, 为了标新立异以及使用的直观性,HTTL采用基于HTML属性的指令,如: <table if="user.role == 'admin'"> <tr foreach="book in books"> <td>${book.title}</td> </tr> </table> 选型方面的区别: 部分优化策略示例: (1) 强类型编译 对于表达式${user.name}的编译: Smarty4j弱类型字节码生成: Object user = context.get("user"); // 无法确定user是Map还是POJO // 反射获取属性的值,而且要运行期判断是user.getName(),还是user.name字段 Object name = ReflectUtil.get(user, "name"); // 接下来name也要反射 Httl强类型字节码生成: User user = (User)context.get("user"); // 通过in="User user"声明类型 String name = user.getName(); // 编译期通过User的字段类型推演name的类型,并在编译期决定使用getName() 如果只是编译成弱类型字节码,性能比解释执行快不了多少,淘宝编译Velocity的测试数据显示,只能比JavaCC的AST解释执行快10%左右,参见附件的PPT。(附件的PPT是蒋江涛在InfoQ大会的演讲稿,是公开的) (2) 对大模板拆分子函数:(未发布) SunJDK缺省对大于5K字节码的方法不进行JIT优化, 所以当模板的内容较大时,会导致生成的字节码也比较大, 通过拆分子函数,可以解决JIT优化问题。 淘宝编译Velocity的测试数据显示,大模板拆分成小模板性能提升35%,参见附件的PPT。 (3) 编译时就将文本编译成字节,加快输出:(未发布) 原编译: writer.write("<table><tr><td>"); writer.write(user.getName()); 改为编译成: private static byte[] final _B1_ = new byte[] {60, 116, 97, 98, 108, 101, 62, 60, 116, 114, 62, 60, 116, 100, 62}; output.write(_B1_); output.write(user.getName().getBytes()); 淘宝编译Velocity的测试数据显示,将String输出预编译为byte[]输出,性能提升50%,参见附件的PPT。 (4) 对同条件if语句优化:(未发布) if (user.role == "admin") { // ... } else if (user.role == "member") { // ... } else { // ... } 优化后: int id = System.identityHashCode(user.role); switch (id) { case 3452345: // 编译时计算"admin"的identityHashCode // ... case 2342452: // 编译时计算"member"的identityHashCode // ... default: // ... } (5) 对于赋值生成的price为局部变量,不put回context: 比如:set="price = price * discount / 100"编译: int price = price * discount / 100; 除非声明out="price",才在模板渲染最后: context.put("price", price); (6) 减少int到Integer等元类型的boxed和unboxed,以及instanceof。 因为模板输出的大量是基本类型和字符串, 比如当输出基本类型时,需要转成String,如果使用format(Object)接口,就会将基本类型装箱, Httl遇到任何类似需要boxed和unboxed的地方,都会重载所有基本类型方法,以减少boxed和unboxed的处理。 出现instanceof的地方也一样,会尽量多态处理。 (7) 所有编译过程都会保持和计算源码位置, 当出错时,错误信息能准确定位到出错行列。 等等。 性能测试: 测试结果:
测试代码: http://code.google.com/p/httl/downloads/list 更多信息参见: http://code.google.com/p/httl HTTL缺省使用Jdk的javax,tools编译字节码,需要500ms左右,如果换成Javassist编译,编译时间可以降到200ms左右,但字节码执行效率略差一点,但每个模板只编译一次,所以编译慢点也能忍受,如果想换成Javassist,只需在httl.properties中加入: compiler=com.googlecode.httl.support.compilers.JavassistCompiler java.version=1.4 注:Javassist不支持1.5的语法,所以要设置java.version=1.4 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|||||||||||||||||||||||||||||||||||||
返回顶楼 | |||||||||||||||||||||||||||||||||||||
发表时间:2011-09-14
就凭这个小测试就说超越velocity
|
|||||||||||||||||||||||||||||||||||||
返回顶楼 | |||||||||||||||||||||||||||||||||||||
发表时间:2011-09-14
听说Smarty4j 也是编译成字节码,那速度相差怎么这么多?刚还看一文章说Smarty4j 很快~~~~~~~~~~~
|
|||||||||||||||||||||||||||||||||||||
返回顶楼 | |||||||||||||||||||||||||||||||||||||
发表时间:2011-09-14
感觉楼主应该说一下httl为什么比其他的快这么多,做了哪些技术优化,像温少一样,有个技术内幕之类的东西。这样才能有人用,否则大家都是一团雾水撒,谁还敢用呢,期待
|
|||||||||||||||||||||||||||||||||||||
返回顶楼 | |||||||||||||||||||||||||||||||||||||
发表时间:2011-09-14
开发阶段,要频繁更改,那样速度会输很多啊。
还有就是html属性,有些项目用于前端工程师写javascript了,而且好几个jquery的插件都用到Html属性,请问,会有影响吗? |
|||||||||||||||||||||||||||||||||||||
返回顶楼 | |||||||||||||||||||||||||||||||||||||
发表时间:2011-09-14
吹牛皮的吧。
|
|||||||||||||||||||||||||||||||||||||
返回顶楼 | |||||||||||||||||||||||||||||||||||||
发表时间:2011-09-14
我不发表意见
|
|||||||||||||||||||||||||||||||||||||
返回顶楼 | |||||||||||||||||||||||||||||||||||||
发表时间:2011-09-14
Engine Compile Run TPS
Freemarker 125ms 16,934ms 590t/s Velocity 110ms 19,278ms 518t/s Smarty4j 78ms 21,653ms 461t/s 10倍???楼主是从哪里算出来的?? |
|||||||||||||||||||||||||||||||||||||
返回顶楼 | |||||||||||||||||||||||||||||||||||||
发表时间:2011-09-14
让牛再飞一会儿吧~~
|
|||||||||||||||||||||||||||||||||||||
返回顶楼 | |||||||||||||||||||||||||||||||||||||
发表时间:2011-09-14
lanxia39 写道 就凭这个小测试就说超越velocity
一个测试用例的数据,确实有失偏颇,测试代码也贴出来了,我用的模板是一个常规的列表页面,相信在应用中大量存在,后续有空我再补其它用例。 |
|||||||||||||||||||||||||||||||||||||
返回顶楼 | |||||||||||||||||||||||||||||||||||||