发生哈希连接时,NonStringExceptions 会消耗大量时间

NonStringExceptions consume considerable time when concatenation of hashes occurs

我们有很多像这样执行散列连接的 FTL 代码:

<#local event_data = event_data + {
   'subaction_name': subactionName
} />

但是,由于以下代码(freemarker.core.AddConcatExpression class' _getAsTemplateModel(Environment env) 方法),这些构造会导致一些开销:

try {
   String s1 = getStringValue(leftModel, left, env);
   if(s1 == null) s1 = "null";
   String s2 = getStringValue(rightModel, right, env);
   if(s2 == null) s2 = "null";
   return new SimpleScalar(s1.concat(s2));
} catch (NonStringException e) {
   if (leftModel instanceof TemplateHashModel && rightModel instanceof TemplateHashModel) {
       if (leftModel instanceof TemplateHashModelEx && rightModel instanceof TemplateHashModelEx) {
           TemplateHashModelEx leftModelEx = (TemplateHashModelEx)leftModel;
           TemplateHashModelEx rightModelEx = (TemplateHashModelEx)rightModel;
           if (leftModelEx.size() == 0) {
               return rightModelEx;
           } else if (rightModelEx.size() == 0) {
               return leftModelEx;
           } else {
               return new ConcatenatedHashEx(leftModelEx, rightModelEx);
           }
       } else {
           return new ConcatenatedHash((TemplateHashModel)leftModel,
                                       (TemplateHashModel)rightModel);
       }
   } else {
       throw e;
   }
}

因为在这种情况下 getStringValue 方法会抛出 NonStringExceptions。 NonStringException 又从 TemplateException 继承了以下构造函数逻辑:

super(getDescription(description, cause));
causeException = cause;
this.env = env;
if(env != null)
{
   StringWriter sw = new StringWriter();
   PrintWriter pw = new PrintWriter(sw);
   env.outputInstructionStack(pw);
   pw.flush();
   ftlInstructionStack = sw.toString();
}
else
{
   ftlInstructionStack = "";
}

无论进一步处理如何,每次都获取完整的指令堆栈。

在我们的案例中,这导致每个页面请求的异常构造函数花费多达 50 毫秒的执行时间,这对整体吞吐量来说非常关键。

有人可以就如何在不触及 FTL 代码的情况下避免这些异常给出一些建议吗?或者,也许可以获得某种补丁,将 TemplateModelHash instanceof 检查移到 AddConcatExpression._getAsTemplateModel 方法中的 catch 块之前?

编辑: freemarker 版本 2.3.19

尝试使用最新稳定的 FreeMarker 版本(目前为 2.3.25),看看速度是否可以接受。 2013-06-13 中的一个提交说:

This reduces TemplateException creation resource usage further (as far as it will be silently handled), as the final message from the blamed expression, tips and so on is only assembled when the message is indeed needed.

2.3.19 早于 2012-02-29 发布。

更新: 我已提交到 2.3.26-nightly,以便回退到哈希添加根本不依赖异常 throwing/catching。不确定这在您的性能问题中有多重要,但它肯定是低效的。