为什么test1()的运行速度比test2()快? [英] Why does test1() run much faster than test2()?

查看:164
本文介绍了为什么test1()的运行速度比test2()快?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

import java.util.Random;


public class Test{
    static int r = new Random().nextInt(2);
    static int a(){
        return r==1 ? 1 :0;
    }

    public static void test1() throws  Exception {
        //
        System.out.println(1403187139018L);
        for (int i = 0; i <   1073741824; i++) {}//*

        // Thread.sleep(20000);
        long d = 0;

        for (int j = 0; j < 10; j++) {
            long y = System.currentTimeMillis();

            for (int x = 0; x < 1073741823; x++) {
                d += r==0?1:0;
            }
            System.out.println((System.currentTimeMillis() -y));
        }
    }

    public static void test2()  throws  Exception{

        // Thread.sleep(20000);
        long d = 0;

        for (int j = 0; j < 10; j++) {
            long y = System.currentTimeMillis();

            for (int x = 0; x < 1073741824; x++) {
                d += r==0?1:0;
            }
            System.out.println((System.currentTimeMillis() -y));

            // System.out.println("time:"+ (System.currentTimeMillis() - y));
        }
    }

    public static void main(String[] args) throws  Exception{
        // Thread.sleep(20000);

        test1();
        test2();

    }

}

运行上面的代码时,得到以下输出:

When I run the above code, I get this output:

32
26
28
28
32
29
35
33
30
31
1321
1308
1324
1277
1348
1321
1337
1413
1287
1331

为什么test1快得多?

Why is test1 much faster ?

除以下内容外没有其他区别:

There is no difference except the followings:

System.out.println(1403187139018L);
for (int i = 0; i <   1073741824; i++) {}//*

此外,test1的时间成本是25-35毫秒,我认为这是难以置信的.我用C语言编写了相同的代码,每个for循环大约需要4秒钟.

Also, the time cost for test1 is 25-35 milliseconds, which I find unbelievable. I wrote the same code in C and it needed about 4 seconds to run every for loop.

这种行为似乎很奇怪.我怎么知道何时添加:

This behavior seems strange. How do I know when to add:

System.out.println(1403187139018L);
for (int i = 0; i <   1073741824; i++) {}//*

此外,如果我更改

r==0?1:0

a()

然后test2()的运行速度比test1()快.

then test2() runs faster than test1().

我得到的输出是:

1403187139018
3726
3729
3619
3602
3797
4362
4498
3816
4143
4368
1673
1386
1388
1323
1296
1337
1294
1283
1235
1460

原始旧版代码: ...

the original legacy code: ...

long t = System.currentTimeMillis();
MappedByteBuffer mbb = map(new File("temp.mmp"), 1024L * 1024 * 1024);

System.out.println("load " + (System.currentTimeMillis() - t));//*
for (int i = 0; i < 2014L * 1024 * 1024; i++) {}//*
int d = 0;
for (int j = 0; j < 10; j++) {
    t = System.currentTimeMillis();
    mbb.position(0);
    mbb.limit(mbb.capacity());

    for (int i = 0; i < mbb.capacity(); i++) {
        d += mbb.get();
    }

    ....
}
System.out.println(d);

推荐答案

影响JIT编译的因素太多:

There are too many factors that affect JIT compilations:

  1. 执行统计信息.在解释器运行方法时,它收集不同的统计信息:执行了哪些路径,采取了哪些分支,看到了哪些类实例等.在test1中,统计信息收集在第一个(空)循环内,因此使JIT编译器误解了实际执行方案.
  2. 类初始化和不常见的陷阱.从test1中删除第一个System.out.println时,并非所有与打印相关的类都被初始化.尝试调用未初始化类的方法会导致不常见的陷阱,从而导致使用新知识对方法进行优化和进一步重新编译.
  3. 当您将r==0?1:0替换为a()时,在test1中收集的错误统计信息会成为一个恶作剧.在已编译的test1中,方法a()从未执行过,因此没有机会进行优化.这就是为什么它比test2慢的原因,而test2是在a()的知识下编译的.
  1. Execution statistics. While interpreter runs a method it collects different statistics: which paths are executed, which branches are taken, which class instances are seen etc. In test1 the statistics is collected inside the first (empty) loop and thus fools the JIT compiler about the real execution scenario.
  2. Class initialization and uncommon traps. When you remove the first System.out.println from test1, not all classes related to printing are initialized. An attempt to invoke a method of an uninitialized class causes uncommon trap which leads to deoptimization and further recompilation of the method using new knowledge.
  3. The wrong statistics collected in test1 plays the bad joke when you replace r==0?1:0 with a(). In compiled test1 the method a() has never been executed before and thus has not had a chance to be optimized. That's why it works slower than test2 which has been compiled with the knowledge of a().

当然,在尝试从头开始编写微基准测试时,很难预测影响JIT编译的所有因素.这就是为什么推荐的对代码进行基准测试的方法是使用已经解决了大多数这些问题的特殊框架.我个人建议 JMH .

Of course, it is hard to predict all factors affecting JIT-compilation when trying to write a microbenchmark from scratch. That's why the recommended way to benchmark your code is using special frameworks where most of these problems have been solved already. I personally suggest JMH.

这篇关于为什么test1()的运行速度比test2()快?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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