1. 表達式引擎選型
如果要做一個規則引擎,需要匹配一組規則集來做決策,此時就需要一個表達式引擎來輔助。
選擇 5 種表達式引擎進行性能對比,從而選擇最優表達式引擎和最優方案。Janino、QLExpress、MEVL、JUEL、FEL。
當然,除了計算性能,還要考慮是否滿足功能,以及是否有安全漏洞等,本文僅進行表達式引擎的性能對比。
2. 性能測試
2.1 測試維度
- 表達式維度:主要採用了3種表達式,表達式的語法在不同的表達式引擎中也不同,詳見3.2 。
- 表達式1: 最常見的場景(多個條件進行and操作):city.equals(‘杭州’) && age<=20
- 表達式2: 包含特殊的操作(contains):city.equals(‘杭州’) && age<=20 && stringList.contains(str)
- 表達式3: 一個稍微複雜一點的語法樹 :a>1 && ((b>1 || c<1) || (a>1 && b<1 && c>1))
- 數據量
- 1000萬
- 2000萬
- 4000萬
2.2 測試方式
根據數據量執行多少次 for 循環,記錄下表達式計算的總耗時,單位毫秒 (ms)。爲了保證一定的差異性,變量賦值的時候,採用變化的值。代碼詳見 3.2 。
2.3 結論
- 表達式1:city.equals(“杭州”) && age<=20
Janino | QL | Mvel (預編譯) | Juel | Fel | |
---|---|---|---|---|---|
1000萬 | 583 | 6885 | 2634 | 3174 | 125065 |
2000萬 | 1171 | 11363 | 4167 | 4318 | 277257 |
4000萬 | 1951 | 22979 | 8544 | 9117 | 519036 |
- 表達式2: city.equals(“杭州”) && age<=20 && stringList.contains(str)
Janino | QL | Mvel (預編譯) | Juel | Fel | |
---|---|---|---|---|---|
1000萬 | 508 | 6473 | 2810 | 2787 | 166865 |
2000萬 | 983 | 12793 | 4627 | 5728 | 339085 |
4000萬 | 2008 | 25595 | 9656 | 11417 | 670728 |
- 表達式3:a>1 && ((b>1 || c<1) || (a>1 && b<1 && c>1))
Janino | QL | Mvel (預編譯) | Juel | Fel | |
---|---|---|---|---|---|
1000萬 | 489 | 3082 | 2206 | 3056 | 167739 |
2000萬 | 947 | 6156 | 3445 | 5950 | 321651 |
4000萬 | 1909 | 12353 | 7284 | 12934 | 642368 |
Janino 表達式引擎的性能最優。
處理速度上,Janino > Mvel(預編譯) > Juel > QL > Fel 。
3. 附錄
3.1 機器配置
本機 Mac 配置:
MacBook Pro (13-inch, 2019, Four Thunderbolt 3 ports)
處理器 2.4 GHz 四核Intel Core i5
內存 16 GB 2133 MHz LPDDR3
圖形卡 Intel Iris Plus Graphics 655 1536 MB
3.2 Java 測試代碼
- Janino
import org.codehaus.commons.compiler.CompilerFactoryFactory;
import org.codehaus.commons.compiler.IExpressionEvaluator;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* Description:
*
* @author mwt
* @version 1.0
* @date 2020/5/21
*/
public class JaninoExpressionTest {
@Test
public void test1() throws Exception {
String ruleExpress = "city.equals(\"杭州\") && age<=20";
long count1 = 1000 * 10000;
System.out.println("\nJaninoExpression1 數據量 1000 萬:");
execute(count1, ruleExpress);
long count2 = 2000 * 10000;
System.out.println("\nJaninoExpression1 數據量 2000 萬:");
execute(count2, ruleExpress);
long count3 = 4000 * 10000;
System.out.println("\nJaninoExpression1 數據量 4000 萬:");
execute(count3, ruleExpress);
}
@Test
public void test2() throws Exception {
String ruleExpress = "city.equals(\"杭州\") && age<=20 && stringList.contains(str)";
long count1 = 1000 * 10000;
System.out.println("\nJaninoExpression2 數據量 1000 萬:");
execute(count1, ruleExpress);
long count2 = 2000 * 10000;
System.out.println("\nJaninoExpression2 數據量 2000 萬:");
execute(count2, ruleExpress);
long count3 = 4000 * 10000;
System.out.println("\nJaninoExpression2 數據量 4000 萬:");
execute(count3, ruleExpress);
}
@Test
public void test3() throws Exception {
String ruleExpress = "a>1 && ((b>1 || c<1) || (a>1 && b<1 && c>1))";
long count1 = 1000 * 10000;
System.out.println("\nJaninoExpression3 數據量 1000 萬:");
execute(count1, ruleExpress);
long count2 = 2000 * 10000;
System.out.println("\nJaninoExpression3 數據量 2000 萬:");
execute(count2, ruleExpress);
long count3 = 4000 * 10000;
System.out.println("\nJaninoExpression3 數據量 4000 萬:");
execute(count3, ruleExpress);
}
private void execute(long count, String expression) throws Exception {
IExpressionEvaluator expressionEvaluator =
CompilerFactoryFactory.getDefaultCompilerFactory().newExpressionEvaluator();
expressionEvaluator.setExpressionType(boolean.class);
expressionEvaluator.setParameters(
new String[]{"city", "age", "stringList", "str", "a", "b", "c"},
new Class[]{String.class, Integer.class, List.class, String.class,
Integer.class, Integer.class, Integer.class}
);
expressionEvaluator.cook(expression);
long start = System.currentTimeMillis();
List<String> stringList = new ArrayList<String>(2);
stringList.add("hello");
stringList.add("world");
Random random = new Random();
for (int i = 0; i < count; i++) {
Object[] arguments = new Object[7];
int age = random.nextInt(50);
if (i % 2 == 0) {
arguments[0] = "杭州";
} else {
arguments[0] = "北京";
}
arguments[1] = age;
arguments[2] = stringList;
if (i % 3 == 0) {
arguments[3] = "hello";
} else if (i % 3 == 1) {
arguments[3] = "world";
} else {
arguments[3] = "anything";
}
arguments[4] = random.nextInt(2);
arguments[5] = random.nextInt(2);
arguments[6] = random.nextInt(2);
Object res = expressionEvaluator.evaluate(arguments);
}
long end = System.currentTimeMillis();
long intervalInMs = end - start;
float avg = (float) count / intervalInMs * 1000;
System.out.println("總耗時毫秒:" + intervalInMs);
System.out.println("每秒處理條數:" + avg);
}
}
- QL
import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressRunner;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* Description:
*
* @author mwt
* @version 1.0
* @date 2020/5/21
*/
public class QLExpressTest {
@Test
public void test1() throws Exception {
String ruleExpress = "city.equals(\"杭州\") && age<=20";
long count1 = 1000 * 10000;
System.out.println("\nQLExpress1 數據量 1000 萬:");
execute(count1, ruleExpress);
long count2 = 2000 * 10000;
System.out.println("\nQLExpress1 數據量 2000 萬:");
execute(count2, ruleExpress);
long count3 = 4000 * 10000;
System.out.println("\nQLExpress1 數據量 4000 萬:");
execute(count3, ruleExpress);
}
@Test
public void test2() throws Exception {
String ruleExpress = "city.equals(\"杭州\") && age<=20 && stringList.contains(str)";
long count1 = 1000 * 10000;
System.out.println("\nQLExpress2 數據量 1000 萬:");
execute(count1, ruleExpress);
long count2 = 2000 * 10000;
System.out.println("\nQLExpress2 數據量 2000 萬:");
execute(count2, ruleExpress);
long count3 = 4000 * 10000;
System.out.println("\nQLExpress2 數據量 4000 萬:");
execute(count3, ruleExpress);
}
@Test
public void test3() throws Exception {
String ruleExpress = "a>1 && ((b>1 || c<1) || (a>1 && b<1 && c>1))";
long count1 = 1000 * 10000;
System.out.println("\nQLExpress3 數據量 1000 萬:");
execute(count1, ruleExpress);
long count2 = 2000 * 10000;
System.out.println("\nQLExpress3 數據量 2000 萬:");
execute(count2, ruleExpress);
long count3 = 4000 * 10000;
System.out.println("\nQLExpress3 數據量 4000 萬:");
execute(count3, ruleExpress);
}
private void execute(long count, String expression) throws Exception {
ExpressRunner runner = new ExpressRunner();
DefaultContext<String, Object> context = new DefaultContext<String, Object>();
long start = System.currentTimeMillis();
List<String> stringList = new ArrayList<String>(2);
stringList.add("hello");
stringList.add("world");
Random random = new Random();
for (int i = 0; i < count; i++) {
int age = random.nextInt(50);
if (i % 2 == 0) {
context.put("city", "杭州");
} else {
context.put("city", "北京");
}
context.put("age", age);
context.put("stringList", stringList);
if (i % 3 == 0) {
context.put("str", "hello");
} else if (i % 3 == 1) {
context.put("str", "world");
} else {
context.put("str", "anything");
}
context.put("a",random.nextInt(2));
context.put("b",random.nextInt(2));
context.put("c",random.nextInt(2));
Object res = runner.execute(expression, context, null, true, false);
}
long end = System.currentTimeMillis();
long intervalInMs = end - start;
float avg = (float) count / intervalInMs * 1000;
System.out.println("總耗時毫秒:" + intervalInMs);
System.out.println("每秒處理條數:" + avg);
}
}
- Mvel
import org.junit.Test;
import org.mvel2.MVEL;
import org.mvel2.ParserContext;
import java.io.Serializable;
import java.util.*;
/**
* Description:
*
* @author mwt
* @version 1.0
* @date 2020/5/22
*/
public class MvelExpressTest {
// =========================== mvel 不編譯,超級慢 ===========================
@Test
public void test11() {
String ruleExpress = "city=='杭州' && age<=20";
long count1 = 1000 * 10000;
System.out.println("\nMvelCompileExpress1 數據量 1000 萬:");
execute1(count1, ruleExpress);
long count2 = 2000 * 10000;
System.out.println("\nMvelCompileExpress1 數據量 2000 萬:");
execute1(count2, ruleExpress);
long count3 = 4000 * 10000;
System.out.println("\nMvelCompileExpress1 數據量 4000 萬:");
execute1(count3, ruleExpress);
}
@Test
public void test12() {
String ruleExpress = "city=='杭州' && age<=20 && stringList.contains(str)";
long count1 = 1000 * 10000;
System.out.println("\nMvelCompileExpress2 數據量 1000 萬:");
execute1(count1, ruleExpress);
long count2 = 2000 * 10000;
System.out.println("\nMvelCompileExpress2 數據量 2000 萬:");
execute1(count2, ruleExpress);
long count3 = 4000 * 10000;
System.out.println("\nMvelCompileExpress2 數據量 4000 萬:");
execute1(count3, ruleExpress);
}
@Test
public void test13() {
String ruleExpress = "a>1 && ((b>1 || c<1) || (a>1 && b<1 && c>1))";
long count1 = 1000 * 10000;
System.out.println("\nMvelCompileExpress3 數據量 1000 萬:");
execute1(count1, ruleExpress);
long count2 = 2000 * 10000;
System.out.println("\nMvelCompileExpress3 數據量 2000 萬:");
execute1(count2, ruleExpress);
long count3 = 4000 * 10000;
System.out.println("\nMvelCompileExpress3 數據量 4000 萬:");
execute1(count3, ruleExpress);
}
// =========================== mvel 先編譯 ===========================
@Test
public void test21() {
String ruleExpress = "city=='杭州' && age<=20";
long count1 = 1000 * 10000;
System.out.println("\nMvelCompileExpress1 數據量 1000 萬:");
execute2(count1, ruleExpress);
long count2 = 2000 * 10000;
System.out.println("\nMvelCompileExpress1 數據量 2000 萬:");
execute2(count2, ruleExpress);
long count3 = 4000 * 10000;
System.out.println("\nMvelCompileExpress1 數據量 4000 萬:");
execute2(count3, ruleExpress);
}
@Test
public void test22() {
String ruleExpress = "city=='杭州' && age<=20 && stringList.contains(str)";
long count1 = 1000 * 10000;
System.out.println("\nMvelCompileExpress2 數據量 1000 萬:");
execute2(count1, ruleExpress);
long count2 = 2000 * 10000;
System.out.println("\nMvelCompileExpress2 數據量 2000 萬:");
execute2(count2, ruleExpress);
long count3 = 4000 * 10000;
System.out.println("\nMvelCompileExpress2 數據量 4000 萬:");
execute2(count3, ruleExpress);
}
@Test
public void test23() {
String ruleExpress = "a>1 && ((b>1 || c<1) || (a>1 && b<1 && c>1))";
long count1 = 1000 * 10000;
System.out.println("\nMvelCompileExpress3 數據量 1000 萬:");
execute2(count1, ruleExpress);
long count2 = 2000 * 10000;
System.out.println("\nMvelCompileExpress3 數據量 2000 萬:");
execute2(count2, ruleExpress);
long count3 = 4000 * 10000;
System.out.println("\nMvelCompileExpress3 數據量 4000 萬:");
execute2(count3, ruleExpress);
}
// =========================== mvel 先編譯,且輸入值類型指定 ===========================
@Test
public void test31() {
String ruleExpress = "city=='杭州' && age<=20";
long count1 = 1000 * 10000;
System.out.println("\nMvelCompileExpress1 數據量 1000 萬:");
execute3(count1, ruleExpress);
long count2 = 2000 * 10000;
System.out.println("\nMvelCompileExpress1 數據量 2000 萬:");
execute3(count2, ruleExpress);
long count3 = 4000 * 10000;
System.out.println("\nMvelCompileExpress1 數據量 4000 萬:");
execute3(count3, ruleExpress);
}
@Test
public void test32() {
String ruleExpress = "city=='杭州' && age<=20 && stringList.contains(str)";
long count1 = 1000 * 10000;
System.out.println("\nMvelCompileExpress2 數據量 1000 萬:");
execute3(count1, ruleExpress);
long count2 = 2000 * 10000;
System.out.println("\nMvelCompileExpress2 數據量 2000 萬:");
execute3(count2, ruleExpress);
long count3 = 4000 * 10000;
System.out.println("\nMvelCompileExpress2 數據量 4000 萬:");
execute3(count3, ruleExpress);
}
@Test
public void test33() {
String ruleExpress = "a>1 && ((b>1 || c<1) || (a>1 && b<1 && c>1))";
long count1 = 1000 * 10000;
System.out.println("\nMvelCompileExpress3 數據量 1000 萬:");
execute3(count1, ruleExpress);
long count2 = 2000 * 10000;
System.out.println("\nMvelCompileExpress3 數據量 2000 萬:");
execute3(count2, ruleExpress);
long count3 = 4000 * 10000;
System.out.println("\nMvelCompileExpress3 數據量 4000 萬:");
execute3(count3, ruleExpress);
}
/**
* mvel 不編譯
*/
private void execute1(long count, String expression) {
long start = System.currentTimeMillis();
Map<String, Object> paramMap = new HashMap<String, Object>();
List<String> stringList = new ArrayList<String>(2);
stringList.add("hello");
stringList.add("world");
Random random = new Random();
for (int i = 0; i < count; i++) {
int age = random.nextInt(50);
if (i % 2 == 0) {
paramMap.put("city", "杭州");
} else {
paramMap.put("city", "北京");
}
paramMap.put("age", age);
paramMap.put("stringList", stringList);
if (i % 3 == 0) {
paramMap.put("str", "hello");
} else if (i % 3 == 1) {
paramMap.put("str", "world");
} else {
paramMap.put("str", "anything");
}
paramMap.put("a", random.nextInt(2));
paramMap.put("b", random.nextInt(2));
paramMap.put("c", random.nextInt(2));
Object res = MVEL.eval(expression, paramMap);
}
long end = System.currentTimeMillis();
long intervalInMs = end - start;
float avg = (float) count / intervalInMs * 1000;
System.out.println("總耗時毫秒:" + intervalInMs);
System.out.println("每秒處理條數:" + avg);
}
/**
* mvel 先編譯
*/
private void execute2(long count, String expression) {
long start = System.currentTimeMillis();
Serializable serializable = MVEL.compileExpression(expression);
Map<String, Object> paramMap = new HashMap<String, Object>();
List<String> stringList = new ArrayList<String>(2);
stringList.add("hello");
stringList.add("world");
Random random = new Random();
for (int i = 0; i < count; i++) {
int age = random.nextInt(50);
if (i % 2 == 0) {
paramMap.put("city", "杭州");
} else {
paramMap.put("city", "北京");
}
paramMap.put("age", age);
paramMap.put("stringList", stringList);
if (i % 3 == 0) {
paramMap.put("str", "hello");
} else if (i % 3 == 1) {
paramMap.put("str", "world");
} else {
paramMap.put("str", "anything");
}
paramMap.put("a", random.nextInt(2));
paramMap.put("b", random.nextInt(2));
paramMap.put("c", random.nextInt(2));
Object res = MVEL.executeExpression(serializable, paramMap);
}
long end = System.currentTimeMillis();
long intervalInMs = end - start;
float avg = (float) count / intervalInMs * 1000;
System.out.println("總耗時毫秒:" + intervalInMs);
System.out.println("每秒處理條數:" + avg);
}
/**
* mvel 先編譯,且輸入值類型指定
*/
private void execute3(long count, String expression) {
long start = System.currentTimeMillis();
ParserContext context = ParserContext.create();
context.addInput("city", String.class);
context.addInput("age", Integer.class);
context.addInput("stringList", List.class);
context.addInput("str", String.class);
context.addInput("a", Integer.class);
context.addInput("b", Integer.class);
context.addInput("c", Integer.class);
Serializable serializable = MVEL.compileExpression(expression);
Map<String, Object> paramMap = new HashMap<String, Object>();
List<String> stringList = new ArrayList<String>(2);
stringList.add("hello");
stringList.add("world");
Random random = new Random();
for (int i = 0; i < count; i++) {
int age = random.nextInt(50);
if (i % 2 == 0) {
paramMap.put("city", "杭州");
} else {
paramMap.put("city", "北京");
}
paramMap.put("age", age);
paramMap.put("stringList", stringList);
if (i % 3 == 0) {
paramMap.put("str", "hello");
} else if (i % 3 == 1) {
paramMap.put("str", "world");
} else {
paramMap.put("str", "anything");
}
paramMap.put("a", random.nextInt(2));
paramMap.put("b", random.nextInt(2));
paramMap.put("c", random.nextInt(2));
Object res = MVEL.executeExpression(serializable, paramMap);
}
long end = System.currentTimeMillis();
long intervalInMs = end - start;
float avg = (float) count / intervalInMs * 1000;
System.out.println("總耗時毫秒:" + intervalInMs);
System.out.println("每秒處理條數:" + avg);
}
}
- Juel
import de.odysseus.el.ExpressionFactoryImpl;
import de.odysseus.el.util.SimpleContext;
import org.junit.Test;
import javax.el.ExpressionFactory;
import javax.el.ValueExpression;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* Description:
*
* @author mwt
* @version 1.0
* @date 2020/5/22
*/
public class JuelExpressTest {
@Test
public void test1() {
String ruleExpress = "city.equals(\"杭州\") && age<=20";
long count1 = 1000 * 10000;
System.out.println("\nJuelExpress1 數據量 1000 萬:");
execute(count1, ruleExpress);
long count2 = 2000 * 10000;
System.out.println("\nJuelExpress1 數據量 2000 萬:");
execute(count2, ruleExpress);
long count3 = 4000 * 10000;
System.out.println("\nJuelExpress1 數據量 4000 萬:");
execute(count3, ruleExpress);
}
@Test
public void test2() {
String ruleExpress = "city.equals(\"杭州\") && age<=20 && stringList.contains(str)";
long count1 = 1000 * 10000;
System.out.println("\nJuelExpress2 數據量 1000 萬:");
execute(count1, ruleExpress);
long count2 = 2000 * 10000;
System.out.println("\nJuelExpress2 數據量 2000 萬:");
execute(count2, ruleExpress);
long count3 = 4000 * 10000;
System.out.println("\nJuelExpress2 數據量 4000 萬:");
execute(count3, ruleExpress);
}
@Test
public void test3() {
String ruleExpress = "a>1 && ((b>1 || c<1) || (a>1 && b<1 && c>1))";
long count1 = 1000 * 10000;
System.out.println("\nJuelExpress3 數據量 1000 萬:");
execute(count1, ruleExpress);
long count2 = 2000 * 10000;
System.out.println("\nJuelExpress3 數據量 2000 萬:");
execute(count2, ruleExpress);
long count3 = 4000 * 10000;
System.out.println("\nJuelExpress3 數據量 4000 萬:");
execute(count3, ruleExpress);
}
private void execute(long count, String expression) {
ExpressionFactory factory = new ExpressionFactoryImpl();
long start = System.currentTimeMillis();
List<String> stringList = new ArrayList<String>(2);
stringList.add("hello");
stringList.add("world");
Random random = new Random();
for (int i = 0; i < count; i++) {
SimpleContext context = new SimpleContext();
int age = random.nextInt(50);
if (i % 2 == 0) {
context.setVariable("city", factory.createValueExpression("杭州", String.class));
} else {
context.setVariable("city", factory.createValueExpression("北京", String.class));
}
context.setVariable("age", factory.createValueExpression(age, Integer.class));
context.setVariable("stringList", factory.createValueExpression(stringList, List.class));
if (i % 3 == 0) {
context.setVariable("str", factory.createValueExpression("hello", String.class));
} else if (i % 3 == 1) {
context.setVariable("str", factory.createValueExpression("world", String.class));
} else {
context.setVariable("str", factory.createValueExpression("anything", String.class));
}
context.setVariable("a", factory.createValueExpression(random.nextInt(2), Integer.class));
context.setVariable("b", factory.createValueExpression(random.nextInt(2), Integer.class));
context.setVariable("c", factory.createValueExpression(random.nextInt(2), Integer.class));
ValueExpression e = factory.createValueExpression(context, "${" + expression + "}", Boolean.class);
}
long end = System.currentTimeMillis();
long intervalInMs = end - start;
float avg = (float) count / intervalInMs * 1000;
System.out.println("總耗時毫秒:" + intervalInMs);
System.out.println("每秒處理條數:" + avg);
}
}
- Fel
import com.greenpineyu.fel.FelEngine;
import com.greenpineyu.fel.FelEngineImpl;
import com.greenpineyu.fel.context.FelContext;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* Description:
*
* @author mwt
* @version 1.0
* @date 2020/5/22
*/
public class FelExpressTest {
@Test
public void test1() {
String ruleExpress = "city.equals(\"杭州\") && age<=20";
long count1 = 1000 * 10000;
System.out.println("\nFelExpress1 數據量 1000 萬:");
execute(count1, ruleExpress);
long count2 = 2000 * 10000;
System.out.println("\nFelExpress1 數據量 2000 萬:");
execute(count2, ruleExpress);
long count3 = 4000 * 10000;
System.out.println("\nFelExpress1 數據量 4000 萬:");
execute(count3, ruleExpress);
}
@Test
public void test2() {
String ruleExpress = "city.equals(\"杭州\") && age<=20 && stringList.contains(str)";
long count1 = 1000 * 10000;
System.out.println("\nFelExpress2 數據量 1000 萬:");
execute(count1, ruleExpress);
long count2 = 2000 * 10000;
System.out.println("\nFelExpress2 數據量 2000 萬:");
execute(count2, ruleExpress);
long count3 = 4000 * 10000;
System.out.println("\nFelExpress2 數據量 4000 萬:");
execute(count3, ruleExpress);
}
@Test
public void test3() {
String ruleExpress = "a>1 && ((b>1 || c<1) || (a>1 && b<1 && c>1))";
long count1 = 1000 * 10000;
System.out.println("\nFelExpress3 數據量 1000 萬:");
execute(count1, ruleExpress);
long count2 = 2000 * 10000;
System.out.println("\nFelExpress3 數據量 2000 萬:");
execute(count2, ruleExpress);
long count3 = 4000 * 10000;
System.out.println("\nFelExpress3 數據量 4000 萬:");
execute(count3, ruleExpress);
}
private void execute(long count, String expression) {
FelEngine fel = new FelEngineImpl();
FelContext context = fel.getContext();
long start = System.currentTimeMillis();
List<String> stringList = new ArrayList<String>(2);
stringList.add("hello");
stringList.add("world");
Random random = new Random();
for (int i = 0; i < count; i++) {
int age = random.nextInt(50);
if (i % 2 == 0) {
context.set("city", "杭州");
} else {
context.set("city", "北京");
}
context.set("age", age);
context.set("stringList", stringList);
if (i % 3 == 0) {
context.set("str", "hello");
} else if (i % 3 == 1) {
context.set("str", "world");
} else {
context.set("str", "anything");
}
context.set("a", random.nextInt(2));
context.set("b", random.nextInt(2));
context.set("c", random.nextInt(2));
Object res = fel.eval(expression, context);
System.out.println(res);
}
long end = System.currentTimeMillis();
long intervalInMs = end - start;
float avg = (float) count / intervalInMs * 1000;
System.out.println("總耗時毫秒:" + intervalInMs);
System.out.println("每秒處理條數:" + avg);
}
}
參考:
http://www.datadriven.top/2018/02/03/%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%BC%95%E6%93%8E%E6%80%A7%E8%83%BD%E6%AF%94%E8%BE%83/index.html
http://www.welkinbai.com/2019/05/30/ql-intro/#1-%E4%BE%9D%E8%B5%96%E5%92%8C%E5%9F%BA%E6%9C%AC%E8%B0%83%E7%94%A8-1
https://bigjun2017.github.io/2018/09/18/hou-duan/java/mvel2.x-yu-fa-zhi-nan/