Which of these pieces of code is faster in Java?

前端 未结 16 1937
囚心锁ツ
囚心锁ツ 2020-11-30 04:25

a) for(int i = 100000; i > 0; i--) {}

b) for(int i = 1; i < 100001; i++) {}

The answer is t

相关标签:
16条回答
  • 2020-11-30 04:46

    On a modern Java implementation this is not true. Summing up the numbers up to one billion as a benchmark:

    Java(TM) SE Runtime Environment 1.6.0_05-b13
    Java HotSpot(TM) Server VM 10.0-b19
    up 1000000000: 1817ms 1.817ns/iteration (sum 499999999500000000)
    up 1000000000: 1786ms 1.786ns/iteration (sum 499999999500000000)
    up 1000000000: 1778ms 1.778ns/iteration (sum 499999999500000000)
    up 1000000000: 1769ms 1.769ns/iteration (sum 499999999500000000)
    up 1000000000: 1769ms 1.769ns/iteration (sum 499999999500000000)
    up 1000000000: 1766ms 1.766ns/iteration (sum 499999999500000000)
    up 1000000000: 1776ms 1.776ns/iteration (sum 499999999500000000)
    up 1000000000: 1768ms 1.768ns/iteration (sum 499999999500000000)
    up 1000000000: 1771ms 1.771ns/iteration (sum 499999999500000000)
    up 1000000000: 1768ms 1.768ns/iteration (sum 499999999500000000)
    down 1000000000: 1847ms 1.847ns/iteration (sum 499999999500000000)
    down 1000000000: 1842ms 1.842ns/iteration (sum 499999999500000000)
    down 1000000000: 1838ms 1.838ns/iteration (sum 499999999500000000)
    down 1000000000: 1832ms 1.832ns/iteration (sum 499999999500000000)
    down 1000000000: 1842ms 1.842ns/iteration (sum 499999999500000000)
    down 1000000000: 1838ms 1.838ns/iteration (sum 499999999500000000)
    down 1000000000: 1838ms 1.838ns/iteration (sum 499999999500000000)
    down 1000000000: 1847ms 1.847ns/iteration (sum 499999999500000000)
    down 1000000000: 1839ms 1.839ns/iteration (sum 499999999500000000)
    down 1000000000: 1838ms 1.838ns/iteration (sum 499999999500000000)
    

    Note that the time differences are brittle, small changes somewhere near the loops can turn them around.

    Edit: The benchmark loops are

            long sum = 0;
            for (int i = 0; i < limit; i++)
            {
                sum += i;
            }
    

    and

            long sum = 0;
            for (int i = limit - 1; i >= 0; i--)
            {
                sum += i;
            }
    

    Using a sum of type int is about three times faster, but then sum overflows. With BigInteger it is more than 50 times slower:

    BigInteger up 1000000000: 105943ms 105.943ns/iteration (sum 499999999500000000)
    
    0 讨论(0)
  • 2020-11-30 04:48

    A better question is;

    Which is easier to understand/work with?

    This is far more important than a notional difference in performance. Personally, I would point out that performance shouldn't be the criteria for determining the difference here. If they didn't like me challenging their assumption on this, I wouldn't be unhappy about not getting the job. ;)

    0 讨论(0)
  • 2020-11-30 04:50

    Such questions have their base on old best-practice recommendations. It's all about comparison: comparing to 0 is known to be faster. Years ago this might have been seen as quite important. Nowadays, especially with Java, I'd rather let the compiler and the VM do their job and I'd focus on writing code that is easies to maintain and understand.

    Unless there are reasons for doing it otherwise. Remember that Java apps don't always run on HotSpot and/or fast hardware.

    0 讨论(0)
  • 2020-11-30 04:54

    The bottom line is that for any non-performance critical application, the difference is probably irrelevant. As others have pointed out there are times when using ++i instead of i++ could be faster, however, especially in for loops any modern compiler should optimize that distinction away.

    That said, the difference probably has to do with the underlying instructions that get generated for the comparison. Testing if a value is equal to 0 is simply a NAND NOR gate. Whereas testing if a value is equal to an arbitrary constant requires loading that constant into a register, and then comparing the two registers. (This probably would require an extra gate delay or two.) That said, with pipelining and modern ALUs I'd be surprised if the distinction was significant to begin with.

    0 讨论(0)
  • 2020-11-30 04:55

    There are really only two ways to answer this question.

    1. To tell you that it really, really doesn't matter, and you're wasting your time even wondering.

    2. To tell you that the only way to know is to run a trustworthy benchmark on your actual production hardware, OS and JRE installation that you care about.

    So, I made you a runnable benchmark you could use to try that out here:

    http://code.google.com/p/caliper/source/browse/trunk/test/examples/LoopingBackwardsBenchmark.java

    This Caliper framework is not really ready for prime time yet, so it may not be totally obvious what to do with this, but if you really care enough you can figure it out. Here are the results it gave on my linux box:

         max benchmark        ns
           2  Forwards         4
           2 Backwards         3
          20  Forwards         9
          20 Backwards        20
        2000  Forwards      1007
        2000 Backwards      1011
    20000000  Forwards   9757363
    20000000 Backwards  10303707
    

    Does looping backwards look like a win to anyone?

    0 讨论(0)
  • 2020-11-30 04:55

    The answer is a (as you probably found out on the website)

    I think the reason is that the i > 0 condition for terminating the loop is faster to test.

    0 讨论(0)
提交回复
热议问题