aviatorscript icon indicating copy to clipboard operation
aviatorscript copied to clipboard

【请教】a.b.c语法糖性能问题

Open JoabYang opened this issue 2 years ago • 2 comments

前提:业务上允许a.b.c中a or b为null,当a or b为null时返回null,且为了方便配置大部分均这样配置 Option设置:Options.NIL_WHEN_PROPERTY_NOT_FOUND=true

性能分析时,发现com.googlecode.aviator.utils.Reflector#fastGetProperty(java.lang.String, java.lang.String[], java.util.Map<java.lang.String,java.lang.Object>, com.googlecode.aviator.utils.Reflector.Target, boolean, int, int)方法中有如下实现 image 通过火焰图分析发现com.googlecode.aviator.runtime.type.AviatorJavaType#tryResolveAsClass方法执行性能损耗极大(如下面的性能分析所示)。

分析该方法的实现逻辑,大概是:当a.b.c中a为null时,对a进行一系列的class类型处理,其目的之一是读取静态变量的前置逻辑。 除此之外该方法还有哪些意图? 如果禁止该方法的执行会丢失哪些功能? 提供禁止执行的选项开关(如添加Options选项)是否是一种解决方案?

附:性能对比实现与结果 实现:

  1. 对com.googlecode.aviator.runtime.type.AviatorJavaType#tryResolveAsClass执行添加开关Options.SWITCH
if (target.innerEnv != null) {
    val = target.innerEnv.get(rName);
    if (val == null && i == 0 && env instanceof Env && RuntimeUtils.getInstance(env).getOptionValue(Options.SWITCH).bool) {
        val = AviatorJavaType.tryResolveAsClass(env, rName);
    }
} else {
    val = fastGetProperty(target.targetObject, rName, PropertyType.Getter);
}
  1. 性能测试单元
package com.googlecode.aviator;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class FastGetPropertyTest {

  static Map env;

  static ExecutorService BEFORE_OPTIMIZE_EXECUTOR = Executors.newFixedThreadPool(5);
  static AviatorEvaluatorInstance beforeOptimizeInstance;
  static Expression beforeOptimizeExpression;

  static ExecutorService AFTER_OPTIMIZE_EXECUTOR = Executors.newFixedThreadPool(5);
  static AviatorEvaluatorInstance afterOptimizeInstance;
  static Expression afterOptimizeExpression;

  static {
    beforeOptimizeInstance = AviatorEvaluator.newInstance();
    beforeOptimizeInstance.setOption(Options.NIL_WHEN_PROPERTY_NOT_FOUND, true);
    beforeOptimizeExpression = beforeOptimizeInstance.compile("a.b.c", true);

    afterOptimizeInstance = AviatorEvaluator.newInstance();
    afterOptimizeInstance.setOption(Options.NIL_WHEN_PROPERTY_NOT_FOUND, true);
    afterOptimizeInstance.setOption(Options.SWITCH, false);
    afterOptimizeExpression = afterOptimizeInstance.compile("a.b.c", true);

    Map env = new HashMap();
    Map a = new HashMap();
    a.put("c", "c");
    env.put("b", a);
  }

  public static void main(String[] args) {
    // 优化前
    for (int i = 0; i < 100000; i++) {
      BEFORE_OPTIMIZE_EXECUTOR.submit(new Runnable() {
        @Override
        public void run() {
          beforeOptimizeExpression.execute(env);
        }
      });
    }
    // 优化后
    for (int i = 0; i < 100000; i++) {
      AFTER_OPTIMIZE_EXECUTOR.submit(new Runnable() {
        @Override
        public void run() {
          afterOptimizeExpression.execute(env);
        }
      });
    }
    BEFORE_OPTIMIZE_EXECUTOR.shutdown();
    AFTER_OPTIMIZE_EXECUTOR.shutdown();
  }
}

结论:

  1. 优化前 image
  2. 优化后 image

JoabYang avatar Mar 23 '23 12:03 JoabYang

@JoabYang 收到,感谢您的反馈。我研究下。

killme2008 avatar Mar 29 '23 09:03 killme2008

或者扩展语法,能否支持类似前端React的写法,让空字符串也能跑 "#foo?.bbb ==nil ? 1 : 2"

zilong avatar May 05 '23 11:05 zilong