java—一个循环中有两个操作,而两个循环执行相同的操作,每个循环一个

sycxhyv7  于 2021-07-09  发布在  Java
关注(0)|答案(4)|浏览(347)

这个问题与这两个循环体或一个(结果相同)相同,但在我的例子中,我使用java。
我有两个循环,运行了十亿次。

int a = 188, b = 144, aMax = 0, bMax = 0;

for (int i = 0; i < 1000000000; i++) {
  int t = a ^ i;
  if (t > aMax) 
    aMax = t;     
}  

for (int i = 0; i < 1000000000; i++) {
  int t = b ^ i;
  if (t > bMax) 
    bMax = t;     
}

在我的机器上运行这两个循环的时间大约是4秒。当我把这两个循环融合到一个循环中并在这个循环中执行所有操作时,它将在2秒内运行。如您所见,琐碎的操作构成了循环内容,因此需要恒定的时间。
我的问题是我从哪里得到了这种性能改进?
我猜想,在两个独立的循环中,性能受到影响的唯一可能的地方是它增加i并检查i是否<10000000002亿次,而如果我将两个循环融合在一起,则只检查10亿次。里面还有什么事吗?
谢谢!

bgibtngc

bgibtngc1#

在我看来,在单循环的情况下,jit可以选择执行循环展开,因此性能稍微好一些

6qfn3psc

6qfn3psc2#

你用服务器了吗?如果没有,你应该-客户端jit不是一个可预测的,也不是一个好的。如果您真的对到底发生了什么感兴趣,可以使用unlockdiagnostic+logcompilation来检查在这两种情况下(一直到生成的程序集)应用了哪些优化。
另外,从您提供的代码中,我看不出您是否进行了预热,是否为同一个jvm运行了一次或多次测试,是否运行了几次(不同的jvm)。无论你考虑的是最佳时间、平均时间还是中间时间,你都会剔除异常值吗?
下面是一个关于编写java微型基准测试的好链接:http://www.ibm.com/developerworks/java/library/j-jtp02225/index.html
编辑:再来一个微标记提示,当心堆栈上的替换:http://www.azulsystems.com/blog/cliff/2011-11-22-what-the-heck-is-osr-and-why-is-it-bad-or-good

q9yhzks0

q9yhzks03#

简而言之,cpu可以并行执行合并循环中的指令,使性能加倍。
第二个回路也可能没有得到有效的优化。这是因为第一个循环将触发要编译的整个方法,而第二个循环将在编译时没有任何可能打乱第二个循环计时的度量。我会将每个循环放在一个单独的方法中,以确保不是这样。
cpu可以并行执行大量独立操作(pentium iii的深度为10,xeon的深度为20)。它尝试并行执行的一个操作是一个分支,使用分支预测,但如果不是每次都使用相同的分支。
我怀疑在循环展开的情况下,您的循环看起来更像下面的循环(在本例中可能是更多的循环展开)

for (int i = 0; i < 1000000000; i += 2) {
  // this first block is run almost in parallel
  int t1 = a ^ i;
  int t2 = b ^ i;
  int t3 = a ^ (i+1);
  int t4 = b ^ (i+1);
  // this block run in parallel
  if (t1 > aMax) aMax = t1;     
  if (t2 > bMax) bMax = t2;     
  if (t3 > aMax) aMax = t3;     
  if (t4 > bMax) bMax = t4;     
}
bjg7j2ky

bjg7j2ky4#

如果不运行预热阶段,可能会对第一个循环进行优化和编译,但不会对第二个循环进行优化和编译,而在合并它们时,会编译整个合并的循环。另外,使用 server 选项和您的代码,大多数得到优化了,因为你不使用结果。
我已经运行了下面的测试,将每个循环以及合并的循环放在它们自己的方法中,并预热jvm以确保所有内容都得到编译。
结果(jvm选项: -server -XX:+PrintCompilation ):
回路1=500ms
回路2=900 ms
合并回路=1300 ms
所以合并的循环稍微快一点,但没有那么多。

public static void main(String[] args) throws InterruptedException {

    for (int i = 0; i < 3; i++) {
        loop1();
        loop2();
        loopBoth();
    }

    long start = System.nanoTime();

    loop1();

    long end = System.nanoTime();
    System.out.println((end - start) / 1000000);

    start = System.nanoTime();
    loop2();
    end = System.nanoTime();
    System.out.println((end - start) / 1000000);

    start = System.nanoTime();
    loopBoth();
    end = System.nanoTime();
    System.out.println((end - start) / 1000000);
}

public static void loop1() {
    int a = 188, aMax = 0;
    for (int i = 0; i < 1000000000; i++) {
        int t = a ^ i;
        if (t > aMax) {
            aMax = t;
        }
    }
    System.out.println(aMax);
}

public static void loop2() {
    int b = 144, bMax = 0;
    for (int i = 0; i < 1000000000; i++) {
        int t = b ^ i;
        if (t > bMax) {
            bMax = t;
        }
    }
    System.out.println(bMax);
}

public static void loopBoth() {
    int a = 188, b = 144, aMax = 0, bMax = 0;

    for (int i = 0; i < 1000000000; i++) {
        int t = a ^ i;
        if (t > aMax) {
            aMax = t;
        }
        int u = b ^ i;
        if (u > bMax) {
            bMax = u;
        }
    }
    System.out.println(aMax);
    System.out.println(bMax);
}

相关问题