处理一组重写方法取决于它是任意的还是交替的

Kha*_*uti 6 java algorithm lambda overriding time-complexity

我有这段代码,我想知道第一个输入和第二个输入的执行时间之间存在差异的原因。我认为它应该花费相同的时间,因为我正在调用相同的方法,但它在两个对象中不执行任何操作。但是 input1 (这是 2 个实例的交替)在我的计算机上花费了 5 秒。input2(这是两个实例之间的任意选择)在我的计算机上花费了 17 秒。

public class Program {


    private static final Runnable FIRST_INSTANCE = () -> {};
    private static final Runnable SECOND_INSTANCE = () -> {};

    private static Runnable[] input1() {
        Runnable[] array = new Runnable[10000];
        for (int i = 0; i < array.length; i++) {
            array[i] = i % 2 == 0 ? FIRST_INSTANCE : SECOND_INSTANCE;
        }
        return array;
    }


    private static Runnable[] input2() {
        Random rnd = new Random(0);
        Runnable[] array = new Runnable[10000];
        for (int i = 0; i < array.length; i++) {
            array[i] = rnd.nextBoolean() ? FIRST_INSTANCE : SECOND_INSTANCE;
        }
        return array;
    }


    public static void main(String[] args) {
        Runnable[] input1 = input1();
        Runnable[] input2 = input2();

        solve(input1);
        solve(input2);

    }

    private static void solve(Runnable[] array) {
        long start = System.nanoTime();
        for (int j = 0; j < 500000; j++) {
            for (Runnable r : array) {
                r.run();
            }
        }
        System.out.println((System.nanoTime() - start) / 1000000000.0);
    }
}
Run Code Online (Sandbox Code Playgroud)

我认为这与缓存无关,因为它们使用相同的实例,并且这不是首先调用哪个的问题,因为我尝试在 input1 之前调用 input2 并且得到相同的结果(input2 总是较慢)。

ilu*_*uxa 2

某种编译器优化正在发挥作用。

我已经用 50000 次迭代而不是 500000 次尝试了你的代码,因为寿命很短。我的时间比你的快大约 10 倍。

首先,我运行了你的代码

0.502928476
1.68480928
Run Code Online (Sandbox Code Playgroud)

然后我尝试运行相同的命令-Djava.compiler=NONE(禁用 JIT):

25.267888581
24.742234792
Run Code Online (Sandbox Code Playgroud)

请注意时机变得多么糟糕。JIT 在这里绝对是一个嫌疑人。

然后我尝试变得input1不那么统一:

array[i] = i % 21 == 0 ? FIRST_INSTANCE : SECOND_INSTANCE;

但这并没有产生什么影响。然后我尝试从以下位置删除该模式input1

array[i] = (int)(Math.sqrt(i) * Math.sqrt(i)) == i ? FIRST_INSTANCE : SECOND_INSTANCE;

0.973357599
1.82497641
Run Code Online (Sandbox Code Playgroud)

性能input1几乎差了一倍。

所以我的结论如下:出于某种原因,数组的一致性对 JIT 很重要:)


再进一步看一下:

input如果我们根本不运行,而是运行input25 次而不是两次,我们会得到:

1.826676411
1.835746098
1.566231165
1.531194014
1.551068832
Run Code Online (Sandbox Code Playgroud)

因此,JIT 似乎在第三个循环中完全启动了。请注意,时间约为 1.5 秒。

现在,如果我们开始运行input1两次,然后继续input2

input1: 2 times
0.507165973
0.509543633
input2: 5 times
1.270496255        <------ WAT?
1.817742481
1.804664757
1.845583904
1.846861045
Run Code Online (Sandbox Code Playgroud)

看起来 JIT 的设置input1确实帮助了input2很多人,但后来被抛弃了,再也没有完全恢复过来