Java 循环优化

标签 java performance optimization

给出以下(直接的)代码:

public class pr1 {

    public static void f1(){
        long sx = 0, s;
        s = System.currentTimeMillis();
        for(long i = 0; i < Integer.MAX_VALUE; ++i){
            sx += i;
        }
        System.out.println("f1(): " + (System.currentTimeMillis() - s));
    }

    public static void f2(){
        long sx = 0, s, i;
        s = System.currentTimeMillis();
        i = Integer.MAX_VALUE;
        while(i-->0){
            sx+=i;
        }
        sx += Integer.MAX_VALUE;
        System.out.println("f2(): " + (System.currentTimeMillis() - s));
    }

    public static void f3(){
        long sx = 0, s, i;
        s = System.currentTimeMillis();
        i = Integer.MAX_VALUE;
        while(--i>0){
            sx+=i;
        }
        sx += Integer.MAX_VALUE;
        System.out.println("f3(): " + (System.currentTimeMillis() - s));
    }

    public static void f4(){
        long sx = 0, s, i;
        s = System.currentTimeMillis();
        i = Integer.MAX_VALUE;
        do{
            sx+=i;
        }while(--i>0);
        System.out.println("f4(): " + (System.currentTimeMillis() - s));
    }

    public static void main(String args[]){
        f1();
        f2();
        f3();
        f4();
    }
}

以及运行代码后的实际结果:

f1(): 5828
f2(): 8125
f3(): 3406
f4(): 3781

你能解释一下巨大的时差吗?从理论上讲,循环实现了相同的功能,但在实践中,四个版本中的每一个似乎都有相关的时间差异。

重复执行后,结果大同小异。

稍后编辑 作为另一个测试,我重写了主要方法:

public static void main(String args[]){
    for(int i = 0; i < 4; ++i){
        f1(); f2(); f3(); f4();
    }
}

新的结果是:

f1(): 5906
f2(): 8266
f3(): 3406
f4(): 3844
f1(): 5843
f2(): 8125
f3(): 3438
f4(): 3859
f1(): 5891
f2(): 8156
f3(): 3406
f4(): 3813
f1(): 5859
f2(): 8172
f3(): 3438
f4(): 3828

重复 10 次:

f1(): 5844
f2(): 8156
f3(): 3453
f4(): 3813
f1(): 5844
f2(): 8218
f3(): 3485
f4(): 3937
f1(): 5985
f2(): 8156
f3(): 3422
f4(): 3781
f1(): 5828
f2(): 8234
f3(): 3469
f4(): 3828
f1(): 5844
f2(): 8328
f3(): 3422
f4(): 3859
f1(): 5844
f2(): 8188
f3(): 3406
f4(): 3797
f1(): 5906
f2(): 8219
f3(): 3422
f4(): 3797
f1(): 5843
f2(): 8203
f3(): 3454
f4(): 3906
f1(): 5844
f2(): 8140
f3(): 3469
f4(): 3812
f1(): 5860
f2(): 8109
f3(): 3422
f4(): 3813

去除循环之间的微积分后,结果还是有点不同:

public class pr2 {

    public static void f1(){
        long sx = 0, s;
        s = System.currentTimeMillis();
        for(long i = 0; i < Integer.MAX_VALUE; ++i);
        System.out.println("f1(): " + (System.currentTimeMillis() - s));
    }

    public static void f2(){
        long sx = 0, s, i;
        s = System.currentTimeMillis();
        i = Integer.MAX_VALUE;
        while(i-->0);
        System.out.println("f2(): " + (System.currentTimeMillis() - s));
    }

    public static void f3(){
        long sx = 0, s, i;
        s = System.currentTimeMillis();
        i = Integer.MAX_VALUE;
        while(--i>0);
        System.out.println("f3(): " + (System.currentTimeMillis() - s));
    }

    public static void f4(){
        long sx = 0, s, i;
        s = System.currentTimeMillis();
        i = Integer.MAX_VALUE;
        do{
        }while(--i>0);
        System.out.println("f4(): " + (System.currentTimeMillis() - s));
    }

    public static void main(String args[]){
        for(int i = 0; i < 2; ++i){
            f1(); f2(); f3(); f4();
        }
    }
}

但是时差还是存在的:

f1(): 3219
f2(): 4859
f3(): 2610
f4(): 3031
f1(): 3219
f2(): 4812
f3(): 2610
f4(): 3062

虚拟机:

java version "1.6.0_20"
Java(TM) SE Runtime Environment (build 1.6.0_20-b02)
Java HotSpot(TM) Client VM (build 16.3-b01, mixed mode, sharing)

后期编辑: 对于第一个版本,我为 javac 使用了 -O 参数。新的结果是:

f1(): 3219
f2(): 4859
f3(): 2610
f4(): 3031

后期编辑

好的,我在家里尝试了相同的代码,使用 Linux 机器:

java version "1.6.0_18"
OpenJDK Runtime Environment (IcedTea6 1.8) (6b18-1.8-0ubuntu1)
OpenJDK Server VM (build 14.0-b16, mixed mode)

而且结果是“正常的”。现在没有问题:

f1(): 7495
f2(): 7418
f3(): 7457
f4(): 7384

最佳答案

您实际上是在对 JVM 进行基准测试,而不是代码。

另见:


更新:好的,这个回答有点草率。使用后缀运算符 (i--) 的循环似乎比使用前缀运算符 (--i) 的循环慢。这可能是真的,因为值在表达式求值期间发生了变化,但编译器需要保留原始值的副本以在表达式中使用。使用前缀运算符避免了保留副本的需要,因为表达式中只会使用更改的值。

另见:

毕竟,这种微优化会在 231 次执行中为您节省一到两秒。你真的也经常执行它吗?我更喜欢可读性而不是过早的优化。

关于Java 循环优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3290233/

相关文章:

android - 数据来自多个 "tables"的 ListView 的优化建议

c# - 应用程序的内存搜索索引占用太多内存 - 有什么建议吗?

java - 我应该如何有效地从日志消息流中提取堆栈跟踪?

java - C3P0Registry mbean 未向 MBeanServer 注册。获取 InstanceNotFoundException

Java 与 ArrayList 的多项式乘法

c++ - 64 位平台上的效率 : pointer vs 32-bit array indexing

c - openmp 在指针数组和指向数组的指针之间的性能差异有什么问题?

C - 如果程序是使用具有所有优化标志的 GCC 构建的,桌面 CPU 的速度限制?

python-3.x - 使用 GEKKO 使用代码解决最佳时间控制问题时出现 IndexError

java - 当哈希表生成巨大的哈希码时会发生什么?