12

我在评估我的 java 代码时遇到了一个大问题。为了简化问题,我编写了以下代码,它们产生了相同的奇怪行为。重要的是方法 run() 和给定的双值率。对于我的运行时测试(在 main 方法中),我将速率设置为 0.5 一次,另一次设置为 1.0。值为 1.0 时,将在每次循环迭代中执行 if 语句,而值为 0.5 时,if 语句将执行一半。出于这个原因,我预计第一种情况的运行时间会更长,但事实恰恰相反。谁能解释一下这个现象??

主要结果:

Test mit rate = 0.5
Length: 50000000, IF executions: 25000856
Execution time was 4329 ms.
Length: 50000000, IF executions: 24999141
Execution time was 4307 ms.
Length: 50000000, IF executions: 25001582
Execution time was 4223 ms.
Length: 50000000, IF executions: 25000694
Execution time was 4328 ms.
Length: 50000000, IF executions: 25004766
Execution time was 4346 ms.
=================================
Test mit rate = 1.0
Length: 50000000, IF executions: 50000000
Execution time was 3482 ms.
Length: 50000000, IF executions: 50000000
Execution time was 3572 ms.
Length: 50000000, IF executions: 50000000
Execution time was 3529 ms.
Length: 50000000, IF executions: 50000000
Execution time was 3479 ms.
Length: 50000000, IF executions: 50000000
Execution time was 3473 ms.

编码

public ArrayList<Byte> list = new ArrayList<Byte>();
public final int LENGTH = 50000000;

public PerformanceTest(){
    byte[]arr = new byte[LENGTH];
    Random random = new Random();
    random.nextBytes(arr);
    for(byte b : arr)
        list.add(b);
}

public void run(double rate){

    byte b = 0;
    int count = 0;

    for (int i = 0; i < LENGTH; i++) {

        if(getRate(rate)){
            list.set(i, b);
            count++;
        }
    }
    System.out.println("Length: " + LENGTH + ", IF executions: " + count);
}

public boolean getRate(double rate){
    return Math.random() < rate;
}

public static void main(String[] args) throws InterruptedException {
    PerformanceTest test = new PerformanceTest();

    long start, end;
    System.out.println("Test mit rate = 0.5");
    for (int i = 0; i < 5; i++) {
        start=System.currentTimeMillis();
        test.run(0.5);
        end = System.currentTimeMillis();
        System.out.println("Execution time was "+(end-start)+" ms.");

        Thread.sleep(500);
    }       
    System.out.println("=================================");
    System.out.println("Test mit rate = 1.0");      
    for (int i = 0; i < 5; i++) {
        start=System.currentTimeMillis();
        test.run(1.0);
        end = System.currentTimeMillis();
        System.out.println("Execution time was "+(end-start)+" ms.");
        Thread.sleep(500);
    }   
}
4

3 回答 3

10

分支错误预测在第一种情况下会破坏性能。虽然第二种情况做了一些工作,但它有点直截了当,所以处理器可以很容易地预测下一步。请参阅此维基百科页面以获取更多信息。

尝试使用 0.7 进行测试。如果我是正确的,那么性能将介于 0.5 和 1.0 之间。

于 2012-09-18T15:11:59.510 回答
9

为了确认您看到了我评论中指出的分支错误预测的影响,我进行了一些测试。表格显示了速率(输入到您的运行方法)、if执行次数和运行时间。

0.0   0             1162
0.1   5,000,892     1204.25
0.2   10,002,410    1236.8
0.3   14,998,226    1264
0.4   19,996,983    1278
0.5   24,998,455    1305.5
0.6   29,998,879    1263.25
0.7   34,999,821    1232.25
0.8   39,999,414    1203.5
0.9   44,998,674    1202
1.0   50,000,000    1176.75

你越接近 0.5,你得到的分支错误预测就越多(每次运行大约一个)。越接近 0 或 1,得到的分支预测就越准确(当 rate 为 0 或 1 时不会出现错误预测)。

因为一张图抵得上一千个字:

在此处输入图像描述

于 2012-09-18T15:40:39.597 回答
0

非常类似于为什么处理排序数组比处理未排序数组更快?幕后也有同样的原因。

于 2012-09-18T15:34:30.597 回答