在Java中,相同代码块的运行时间不同.这是为什么? [英] Running time of the same code blocks is different in java. why is that?

查看:67
本文介绍了在Java中,相同代码块的运行时间不同.这是为什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码.我只想检查代码块的运行时间.错误地,我再次复制并粘贴了相同的代码,并得到了有趣的结果.尽管代码块相同,但运行时间不同.而且 code block 1 比其他代码花费更多的时间.如果我将代码块切换为(例如,我将代码块4移至顶部),则代码块4将比其他代码花费更多的时间.

I had the below code. I just wanted to check the running time of a code block. And mistakenly i had copied and pasted the same code again and get an interesting result. Though the code block is the same the running times are different. And the code block 1 taking more time than the others. If i switch the code blocks (say i move the code blocks 4 to the top) then code block 4 will be taking more time than others.

我在代码块中使用了两种不同类型的数组来检查它是否依赖于此.结果是一样的.如果代码块具有相同类型的数组,则最上面的代码块将花费更多时间.参见下面的代码和指定的输出.

I used two different types of Arrays in my code blocks to check it depends on that. And the result is same. If the code blocks has the same type of arrays then the top most code block is taking more time. See the below code and the given out put.

public class ABBYtest {

public static void main(String[] args) {
    long startTime;
    long endTime;

    //code block 1
    startTime = System.nanoTime();
    Long a[] = new Long[10];
    for (int i = 0; i < a.length; i++) {
        a[i] = 12l;
    }
    Arrays.sort(a);
    endTime = System.nanoTime();
    System.out.println("code block (has Long array) 1 = " + (endTime - startTime));

    //code block 6
    startTime = System.nanoTime();
    Long aa[] = new Long[10];
    for (int i = 0; i < aa.length; i++) {
        aa[i] = 12l;
    }
    Arrays.sort(aa);
    endTime = System.nanoTime();
    System.out.println("code block (has Long array) 6 = " + (endTime - startTime));


    //code block 7
    startTime = System.nanoTime();
    Long aaa[] = new Long[10];
    for (int i = 0; i < aaa.length; i++) {
        aaa[i] = 12l;
    }
    Arrays.sort(aaa);
    endTime = System.nanoTime();
    System.out.println("code block (has Long array) 7 = " + (endTime - startTime));

    //code block 2
    startTime = System.nanoTime();
    long c[] = new long[10];
    for (int i = 0; i < c.length; i++) {
        c[i] = 12l;
    }
    Arrays.sort(c);
    endTime = System.nanoTime();
    System.out.println("code block (has long array) 2 = " + (endTime - startTime));

    //code block 3
    startTime = System.nanoTime();
    long d[] = new long[10];
    for (int i = 0; i < d.length; i++) {
        d[i] = 12l;
    }
    Arrays.sort(d);
    endTime = System.nanoTime();
    System.out.println("code block (has long array) 3 = " + (endTime - startTime));

    //code block 4
    startTime = System.nanoTime();
    long b[] = new long[10];
    for (int i = 0; i < b.length; i++) {
        b[i] = 12l;
    }
    Arrays.sort(b);
    endTime = System.nanoTime();
    System.out.println("code block (has long array) 4 = " + (endTime - startTime));

    //code block 5
    startTime = System.nanoTime();
    Long e[] = new Long[10];
    for (int i = 0; i < e.length; i++) {
        e[i] = 12l;
    }
    Arrays.sort(e);
    endTime = System.nanoTime();
    System.out.println("code block (has Long array) 5 = " + (endTime - startTime));


}
}

运行时间:

代码块(具有长数组)1 = 802565

代码块(具有长数组)6 = 6158

代码块(具有长数组)7 = 4619

代码块(具有长数组)2 = 171906

代码块(具有长数组)3 = 4105

代码块(具有长数组)4 = 3079

代码块(具有长数组)5 = 8210

我们可以看到,包含 Long数组的第一个代码块比包含 Long数组的其他代码块要花费更多的时间.它与包含 long array 的第一个代码块相同.

As we can see the first code block which contains the Long array will take more time than others which contain Long arrays. And it is the same for the first code block which contains long array.

任何人都可以解释这种行为.还是我在这里做错了?

Can anyone explain this behavior. or Am i doing some mistake here ??

推荐答案

错误的基准测试.错误原因的详尽列表:

Faulty benchmarking. The non exhaustive list of what is wrong:

  • 不进行预热:单次测量几乎总是错误的;
  • 在单个方法中混合几个代码路径:我们可能会开始使用仅对方法中的第一个循环可用的执行数据来编译该方法;
  • 来源是可预测的:如果循环进行编译,我们实际上可以预测结果;
  • 结果已消除死代码:如果循环可以编译,我们可以将循环丢掉
  • No warmup: single shot measurements are almost always wrong;
  • Mixing several codepaths in the single method: we probably start compiling the method with the execution data available only for the first loop in the method;
  • Sources are predictable: should the loop compile, we can actually predict the result;
  • Results are dead-code eliminated: should the loop compile, we can throw the loop it away

您可以使用 jmh 来正确地做到这一点:

Here is how you do it arguably right with jmh:

@OutputTimeUnit(TimeUnit.NANOSECONDS)
@BenchmarkMode(Mode.AverageTime)
@Warmup(iterations = 3, time = 1)
@Measurement(iterations = 3, time = 1)
@Fork(10)
@State(Scope.Thread)
public class Longs {

    public static final int COUNT = 10;

    private Long[] refLongs;
    private long[] primLongs;

    /*
     * Implementation notes:
     *   - copying the array from the field keeps the constant
     *     optimizations away, but we implicitly counting the
     *     costs of arraycopy() in;
     *   - two additional baseline experiments quantify the
     *     scale of arraycopy effects (note you can't directly
     *     subtract the baseline scores from the tests, because
     *     the code is mixed together;
     *   - the resulting arrays are always fed back into JMH
     *     to prevent dead-code elimination
     */

    @Setup
    public void setup() {
        primLongs = new long[COUNT];
        for (int i = 0; i < COUNT; i++) {
            primLongs[i] = 12l;
        }

        refLongs = new Long[COUNT];
        for (int i = 0; i < COUNT; i++) {
            refLongs[i] = 12l;
        }
    }

    @GenerateMicroBenchmark
    public long[] prim_baseline() {
        long[] d = new long[COUNT];
        System.arraycopy(primLongs, 0, d, 0, COUNT);
        return d;
    }

    @GenerateMicroBenchmark
    public long[] prim_sort() {
        long[] d = new long[COUNT];
        System.arraycopy(primLongs, 0, d, 0, COUNT);
        Arrays.sort(d);
        return d;
    }

    @GenerateMicroBenchmark
    public Long[] ref_baseline() {
        Long[] d = new Long[COUNT];
        System.arraycopy(refLongs, 0, d, 0, COUNT);
        return d;
    }

    @GenerateMicroBenchmark
    public Long[] ref_sort() {
        Long[] d = new Long[COUNT];
        System.arraycopy(refLongs, 0, d, 0, COUNT);
        Arrays.sort(d);
        return d;
    }

}

...这将产生:

Benchmark                   Mode   Samples         Mean   Mean error    Units
o.s.Longs.prim_baseline     avgt        30       19.604        0.327    ns/op
o.s.Longs.prim_sort         avgt        30       51.217        1.873    ns/op
o.s.Longs.ref_baseline      avgt        30       16.935        0.087    ns/op
o.s.Longs.ref_sort          avgt        30       25.199        0.430    ns/op

在这一点上,您可能会开始怀疑为什么对 Long [] 进行排序和对 long [] 进行排序会花费不同的时间.答案就在于 Array.sort()重载:OpenJDK通过不同的算法(使用TimSort的引用,使用双轴quicksort的基元)对基元数组和引用数组进行排序.这是使用 -Djava.util.Arrays.useLegacyMergeSort = true 选择另一种算法的亮点,这又落到了合并引用的排序上:

At this point you may start to wonder why sorting Long[] and sorting long[] takes different time. The answer lies in the Array.sort() overloads: OpenJDK sorts primitive and reference arrays via different algos (references with TimSort, primitives with dual-pivot quicksort). Here's the highlight of choosing another algo with -Djava.util.Arrays.useLegacyMergeSort=true, which falls back to merge sort for references:

Benchmark                   Mode   Samples         Mean   Mean error    Units
o.s.Longs.prim_baseline     avgt        30       19.675        0.291    ns/op
o.s.Longs.prim_sort         avgt        30       50.882        1.550    ns/op
o.s.Longs.ref_baseline      avgt        30       16.742        0.089    ns/op
o.s.Longs.ref_sort          avgt        30       64.207        1.047    ns/op

希望可以帮助解释差异.

Hope that helps to explain the difference.

上面的解释几乎没有涉及排序的性能.当使用不同的源数据(包括可用的预排序子序列,它们的模式和游程长度,数据本身的大小)呈现时,性能会有很大不同.

The explanation above barely scratch the surface about the performance of sorting. The performance is very different when presented with different source data (including available pre-sorted subsequences, their patterns and run lengths, sizes of the data itself).

这篇关于在Java中,相同代码块的运行时间不同.这是为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆