我回答了这个问题 https://stackoverflow.com/questions/25234401/which-is-a-better-practice-for-if-else-condition/25234523并在运行代码时注意到一些让我感兴趣的东西。问题的一部分是关于各种类型的相同条件检查的性能,例如:
if (x > 0) {
if (y > 0) {
if (z > 0) {
if (complexCondition()) {
noOp();
}
}
}
}
versus
if (x > 0 && y > 0 && z > 0 && complexCondition()) {
noOp();
}
我写了一个程序,计算执行一定次数的迭代需要多长时间,结果是我不明白的。
这是我的程序在我的计算机上的输出(Win 8.1 64 位、javac 1.8.0_11 (Oracle)、java 1.0.0_11 (Java SE、Oracle)。我已经多次运行每个试验,它们产生可重复的结果。
x = 9, y = 2, z = 8, countTrials = 1, iterationsPerTrial = 2736000
Method Average Runtime(ns)
guardIf() 5746173
multipleIf() 4868180
chainedIf() 9316172
x = 9, y = 2, z = 8, countTrials = 100, iterationsPerTrial = 2736000
guardIf() 1642750
multipleIf() 1121897
chainedIf() 1739522
x = -1, y = 2, z = 8, countTrials = 1, iterationsPerTrial = 2736000 // I expect shorter results with x = -1, because they all short curcuit
guardIf() 9245313
multipleIf() 8728608
chainedIf() 11718332
x = -1, y = 2, z = 8, countTrials = 100, iterationsPerTrial = 2736000
guardIf() 1754279
multipleIf() 1611278
chainedIf() 4947295
毫秒测量(通过以下方式实现)org.apache.commons.lang3.time.StopWatch
)
x = 9, y = 2, z = 8, countTrials = 1, iterationsPerTrial = Integer.MAX_VALUE
Method Average Runtime(ms)
guardIf() 1664
multipleIf() 1095
chainedIf() 1654
x = -1, y = 2, z = 8, countTrials = 1, iterationsPerTrial = Integer.MAX_VALUE
Method Average Runtime(ms)
guardIf() 4886
multipleIf() 4926
chainedIf() 4862
x = 9, y = 2, z = 8, countTrials = 10, iterationsPerTrial = Integer.MAX_VALUE
Method Average Runtime(ms)
guardIf() 1673
multipleIf() 1108
chainedIf() 1682
x = -1, y = 2, z = 8, countTrials = 10, iterationsPerTrial = Integer.MAX_VALUE
Method Average Runtime(ms)
guardIf() 4364
multipleIf() 4363
chainedIf() 4877
为什么所有方法的运行都需要更长的时间(在这种情况下chainIf
,几乎多了 300% 的时间)当他们检查的值允许他们全部短路时?
我已经用调试器逐步完成了所有这些,并且它们实际上确实短路了(正如我所期望的)。我检查了字节码并且chainedIf()
and multipleIf()
完全相同。我感到困惑和好奇。
我不确定我执行测量的方式是否存在一些缺陷,因此我在下面包含了我的程序。
节目来源
class TrialResult {
public long GuardIf = 0;
public long MultipleIf = 0;
public long ChainedIf = 0;
public TrialResult(long guardIf, long multipleIf, long chainedIf) {
this.GuardIf = guardIf;
this.MultipleIf = multipleIf;
this.ChainedIf = chainedIf;
}
}
public class Program {
private int x;
private int y;
private int z;
public static void main(String[] args) {
Program program = new Program();
List<TrialResult> trials = new ArrayList<TrialResult>();
int countTrials = 1;
for (int j = 0; j < countTrials; j++) {
long t0 = 0, t1 = 0;
t0 = System.nanoTime();
for (long i = 0; i < 2073600; i++) {
program.chainedIf();
}
t1 = System.nanoTime();
long chainIf = t1 - t0;
t0 = System.nanoTime();
for (long i = 0; i < 2073600; i++) {
program.multipleIf();
}
t1 = System.nanoTime();
long multipleIf = t1 - t0;
t0 = System.nanoTime();
for (long i = 0; i < 2073600; i++) {
program.guardIf();
}
t1 = System.nanoTime();
long guardIf = t1 - t0;
System.out.printf("Trial %d completed\r\n", j+1);
trials.add(new TrialResult(guardIf, multipleIf, chainIf));
}
long chainIf = 0, multipleIf = 0, guardIf = 0;
for (TrialResult r : trials) {
chainIf += r.ChainedIf;
multipleIf += r.MultipleIf;
guardIf += r.GuardIf;
}
System.out.printf("%d, %d, %d", guardIf / trials.size(), multipleIf / trials.size(), chainIf / trials.size());
}
private Program() {
x = 9;
y = 2;
z = 8;
}
private void chainedIf() {
if (x > 0) {
if (y > 0) {
if (z > 0) {
if (complexCondition()) {
noOp();
}
}
}
}
}
private void multipleIf() {
if (x > 0 && y > 0 && z > 0 && complexCondition()) {
noOp();
}
}
public void guardIf() {
if (x <= -1) {
return;
}
if (y <= -1) {
return;
}
if (z <= -1) {
return;
}
if (!complexCondition()) {
return;
}
noOp();
}
private boolean complexCondition() {
return (x > 0 &&
y < x &&
y + z > x
);
}
private void noOp() {
return;
}
}