【发布时间】:2013-06-29 13:01:41
【问题描述】:
我已经编写了自己的数学解析器,但由于某种原因,当我尝试分析解析器时,它需要越来越多的时间来解析。
为了测试,我使用了这个输入:Cmd.NUM_9,Cmd.NUM_0,Cmd.NUM_0,Cmd.DIV,Cmd.NUM_2,Cmd.ADD,Cmd.NUM_6,Cmd.MULT,Cmd.NUM_3
单次执行~1.7ms
3000 次重复 ~ 1,360 毫秒
6000 次重复 ~ 5,290 毫秒
9000 次重复 ~11,800 毫秒
分析器说 64% 的时间都花在了这个函数上: 这是我允许隐式乘法的函数。
private void enableImplicitMultiplication(ArrayList<Cmd> input) {
int input_size = input.size();
if (input_size<2) return;
for (int i=0; i<input_size; i++) {
Cmd cmd = input.get(i);
if (i>0) {
Cmd last = input.get(i-1);
// [EXPR1, EXPR2] => [EXPR1, MULT, EXPR2]
boolean criteria1 = Cmd.exprnCmds.contains(cmd) && Cmd.exprnCmds.contains(last);
// [CBRAC, OBRAC] => [CBRAC, MULT, OBRAC]
// [NUM_X, OBRAC] => [NUM_X, MULT, OBRAC]
boolean criteria2 = cmd==Cmd.OBRAC && (last==Cmd.CBRAC || Cmd.constantCmds.contains(last));
// [CBRAC, NUM_X] => [CBRAC, MULT, NUM_X]
boolean criteria3 = last==Cmd.CBRAC && Cmd.constantCmds.contains(cmd);
if (criteria1 || criteria2 || criteria3) {
input.add(i++, Cmd.MULT);
}
}
}
}
这是怎么回事??
我这样重复:
public static void main(String[] args) {
Cmd[] iArray = {
Cmd.NUM_9,Cmd.NUM_0,Cmd.NUM_0,Cmd.DIV,Cmd.NUM_2,Cmd.ADD,Cmd.NUM_6,Cmd.MULT,Cmd.NUM_3
};
ArrayList<Cmd> inputArray = new ArrayList<Cmd>(Arrays.asList(iArray));
DirtyExpressionParser parser = null;
int repeat=9000;
double starttime = System.nanoTime();
for (int i=0; i<repeat; i++) {
parser = new DirtyExpressionParser(inputArray);
}
double endtime = System.nanoTime();
System.out.printf("Duration: %.2f ms%n",(endtime-starttime)/1000000);
System.out.println(parser.getResult());
}
构造函数如下所示:
public DirtyExpressionParser(ArrayList<Cmd> inputArray) {
enableImplicitMultiplication(inputArray); //executed once for each repeat
splitOnBrackets(inputArray); //resolves inputArray into Expr objects for each bracket-group
for (Expr expr:exprArray) {
mergeAndSolve(expr);
}
}
【问题讨论】:
-
分析器是否指出哪一行代码花费的时间最多?
-
我认为这里的问题是 contains 的调用
-
否 - 我使用 NetBeans IDE 进行分析,它只是给了我一个函数列表及其累积执行时间
-
你能把 if (i>0) 放在 input.add() 附近吗?这可能使所有情况下的执行时间几乎相等。
-
在 20000 次迭代后,它将开始检查包含 10s 的数千个事物的列表。经过一百万次迭代后,它将检查 1000000 个元素的输入列表。所以这是 O(N*N) (最坏条件)算法,使得执行时间呈指数增长。也许您可以将它们全部添加并在最后只检查一次,如果可能的话删除不必要的。
标签: java performance for-loop