B6.常见问题
B6.常见问题
01.如何调试,debug解析
调试主要集中在Parse和RnaEngine执行上,因此logger只在此2处存在。 米波工程本身的test中,slf4j的日志基本是trace,因此在其他工程引入时, 需要把设置pro.fessional.meepo
的级别为trace
。
如果通过日志,不能调试到位,可以通过继承Parser,调用protected方法。
如果发生 Class path contains multiple SLF4J bindings等错误提示, 直接exclude meepo工程对slf4j的依赖即可。
02.有关性能和线程安全
模板引擎都是,一次解析,多次使用的,并增加了预编译或缓存。
米波解析时,Parse本身基于字符串分析,仅在有查找
的指令中使用正则, 通常建议,解析的过程需要在单线程内进行,多次解析或竞争毫无意义。
合并使用时,如果不存在Rng
类指令,是静态字符串拼接,首次拼接,后续缓存。 拼接过程中,预分配刚好够的buff,避免扩容。性能高于多次的原生String拼接。
无Rng
指令时,线程安全且碎片极少,可以放心使用。当存在Rng
指令时, 性能和线程安全,取决于执行引擎和传入的context。
根据benchmark的测试(for+if+function)结果,meepo的性能远高于Freemarker
Benchmark | Mode | Cnt | Score | Error | Units |
---|---|---|---|---|---|
Meepo.benchmark | thrpt | 50 | 24177.507 ± | 493.546 | ops/s |
Freemarker.benchmark | thrpt | 50 | 18152.915 ± | 928.830 | ops/s |
Mustache.benchmark | thrpt | 50 | 22565.064 ± | 154.915 | ops/s |
Pebble.benchmark | thrpt | 50 | 34311.017 ± | 248.283 | ops/s |
Rocker.benchmark | thrpt | 50 | 37499.123 ± | 1275.888 | ops/s |
Thymeleaf.benchmark | thrpt | 50 | 5406.186 ± | 177.424 | ops/s |
Trimou.benchmark | thrpt | 50 | 19718.903 ± | 669.759 | ops/s |
Velocity.benchmark | thrpt | 50 | 18956.594 ± | 766.578 | ops/s |
03.如何调教性能
运行MeepoAsyncProfile的main,然后使用async-profiler
mvn clean
mvn -Dmaven.test.skip=false test
mvn dependency:copy-dependencies -DincludeScope=runtime -DoutputDirectory=target/lib
# 启动一个大循环,也可以在IDE中直接运行
java -cp target/classes:target/test-classes\
:target/lib/slf4j-api-1.7.30.jar\
:target/lib/annotations-19.0.0.jar \
pro.fessional.meepo.benchmark.MeepoAsyncProfile
# 获取 pid
jps
# 使用 async-profiler生成svg火焰图
#/Users/trydofor/Applications-cli/async-profiler-1.8.2/profiler.sh
profiler.sh -d 30 -f meepo-profile.svg $pid
和性能有关的细节非常之多,对应模板引擎,主要集中在字符处理技巧上。
- zero-copy,因为String的特性,尽量使用
char[]
代替完成copy - array的赋值,尽量使用System.arraycopy
- hashCode和equals方法,if条件中的短路计算
- 基本类型的toString
- buffer类,避免扩容,线程安全下尽量复用
04.米波语法解析非lexer
正统的语法解析,一般分为词法和语法分析两步。
- 先是进行词法分析,将输入转换成一个一个的Token
- 然后是进行语法分析。一个一个的Token组成语句,对应一定的语法。
米波采用的是硬头皮有限状态死磕法,以便简单处理动态MEEPO头尾和BKB块。
05.如何记住米波的破语法
米波的命名十分简单,如果你了解dota
,vi
和2020的新冠。
- DNA,就是静态替换,目的是做模板中间件,翻译模板
- RNA,具有动态性,支持了for和if,以及engine扩展。
- 各指令的语法,均类似
vi
的s/find/replace/g
替换。 - 米波嘴上说区分大小写,实际上自身的指令支持大小写。
06.如何输入空字符串和引号
在指令中,引号和空白有特殊处理,
- 两个双引号
""
,就是空字符串。 - 而引号需要转义
\"
,才是引号。
07.像其他模板一样做斑马线
Meepo的出发点是模板只负责显示,不负责计算,逻辑结果应该在model预设。 因此要做一个单元格背景的奇偶线效果,在米波中比较费劲,但也能实现。
- 直接在model中生成好样式
- 自定义引擎,计算style
- 使用 USE it._count|mod,如 each-c7s1f7-i1.htm
- 使用 WHEN it._count|mod,如 each-c7s1f7-i2.htm
08.字面量表示数字和Boolean
引擎中,DNA都是静态的字符串替换,RNA都是从内部获取数据。 仅在管道符链式处理时,需从模板读入数据,需要类型支持。
- Number型 - 详见管道符链接函数,链式处理
- Boolean型, TRUE,FALSE - 同上
- 字符串形态需要双引号,如
"TRUE"
,"3.14"
- 以上之外,都为
RefStr
,即先从环境内取值,null时返回此字符串。