对于任何语言来讲,循环永远是非分布式系统的性能的最大杀手,循环中的任何一个简单的语句对性能都是有影响的,只是影响的大小不同而已。第一个例子中的影响是比较大的,不同的实现方法的时间开销不同,然后这个微小的差异被循环次数放大后就非常的明显(3倍),而第二个例子,其本质是减少了循环执行的次数,虽然总的循环次数是一样的,但是最耗时的操作的执行次数被减少到1/10,所以产生的差异是非常巨大的(8倍)。我们再来看一个很不起眼的微小差异带来的影响:
public class GoogleFn {
private static int MAX = 132000000;

private static int MAX2 = MAX / 10;

private static int count(int n) {
int count = 0;
while (n > 0) {
int mod = n % 10;
if (mod == 1)
count++;
n = n / 10;
}
return count;
}

    private static void method1() {
long start = System.currentTimeMillis();
int result = 0;
for (int i = 0; i < MAX2; i++) {
int number = i * 10;
int value = count(number);
for (int j = 0; j < 10; j++) {
result += value;
if (j == 1) {
result++;
}
int x = number + j;
if (x != 0 && result == x) {
print(x, start);
}
}
}
}

private static void method2() {
long start = System.currentTimeMillis();
int result = 0;
for (int i = 0; i < MAX2; i++) {
int number = i * 10;
int value = count(number);
for (int j = 0; j < 10; j++) {
result += value;
if (j == 1) {
result++;
}
int x = number + j;
if (result == x && x != 0) {
print(x, start);
}
}
}
}

private static void print(int i, long start) {
System.out.println(“Find ” + i + “, ” + (System.currentTimeMillis() – start) + “ms”);
}

public static void main(String[] args) {
method1();
method2();
}
}
运行结果:
Find 1, 0ms
Find 199981, 16ms
Find 199982, 16ms
Find 199983, 16ms
Find 199984, 16ms
Find 199985, 16ms
Find 199986, 16ms
Find 199987, 16ms
Find 199988, 16ms
Find 199989, 16ms
Find 199990, 16ms
Find 200000, 16ms
Find 200001, 16ms
Find 1599981, 63ms
Find 1599982, 63ms
Find 1599983, 63ms
Find 1599984, 63ms
Find 1599985, 63ms
Find 1599986, 63ms
Find 1599987, 78ms
Find 1599988, 78ms
Find 1599989, 78ms
Find 1599990, 78ms
Find 2600000, 110ms
Find 2600001, 110ms
Find 13199998, 531ms
Find 35000000, 1453ms
Find 35000001, 1453ms
Find 35199981, 1453ms
Find 35199982, 1453ms
Find 35199983, 1453ms
Find 35199984, 1453ms
Find 35199985, 1453ms
Find 35199986, 1453ms
Find 35199987, 1453ms
Find 35199988, 1453ms
Find 35199989, 1453ms
Find 35199990, 1453ms
Find 35200000, 1453ms
Find 35200001, 1453ms
Find 117463825, 5000ms
Find 1, 0ms
Find 199981, 16ms
Find 199982, 16ms
Find 199983, 16ms
Find 199984, 16ms
Find 199985, 16ms
Find 199986, 16ms
Find 199987, 16ms
Find 199988, 16ms
Find 199989, 16ms
Find 199990, 16ms
Find 200000, 16ms
Find 200001, 16ms
Find 1599981, 63ms
Find 1599982, 63ms
Find 1599983, 63ms
Find 1599984, 63ms
Find 1599985, 63ms
Find 1599986, 63ms
Find 1599987, 78ms
Find 1599988, 78ms
Find 1599989, 78ms
Find 1599990, 78ms
Find 2600000, 109ms
Find 2600001, 109ms
Find 13199998, 516ms
Find 35000000, 1438ms
Find 35000001, 1438ms
Find 35199981, 1438ms
Find 35199982, 1438ms
Find 35199983, 1438ms
Find 35199984, 1438ms
Find 35199985, 1438ms
Find 35199986, 1438ms
Find 35199987, 1438ms
Find 35199988, 1438ms
Find 35199989, 1438ms
Find 35199990, 1438ms
Find 35200000, 1438ms
Find 35200001, 1438ms
Find 117463825, 4938ms

注意我们的MAX值比以前的例子放大了10倍,因为这个例子的差异比较小,值太小看不出差异,注意到两个方法的不同了吗?对,仅仅是if里面的条件换了个位置:
x != 0 && result == x  -》 result == x && x != 0
你还可以稍稍修改下代码,把后面的那个的&& x != 0去掉,你会发现它的结果和这个结果很类似。
这个原理就是&&运算符的短路原理,如果前面的条件不为true,那么后面的计算不被执行。
所以循环中的任何代码都要比较小心,即使一点细小的不同都会在循环的放大作用下产生一些不好的结果。

PS: 条件判断中有多个并列条件时,前面放的应该是最少满足的条件,这样可以更好的过滤。

  1. Google面试题解说性能之一:字符串运算VS数字运算

  2. Google面试题解说性能之二:分析问题

  3. Google面试题解说性能之三:不要小看循环中的任何一个语句

  4. Google面试题解说性能之四:优化无止境

  5. Google面试题解说性能之五:人比电脑聪明

  6. Google面试题解说性能之六:数学显神威

  7. Google面试题解说性能之七:缓存中间结果

  8. Google面试题解说性能之八:工欲善其事必先利其器

  9. Google面试题解说性能之总结

(Visited 55 times, 1 visits today)