I wrote two pieces of code, almost exactly the same, but one runs much faster than the other (Java)

huangapple go评论79阅读模式
英文:

I wrote two pieces of code, almost exactly the same, but one runs much faster than the other (Java)

问题

我运行了这段代码:(外部循环运行了100次,内部循环运行了10亿次。)

long l = 0;

for(int i = 0; i < 100; i++)
    for(int j = 0; j < 1000000000; j++)
        l++;

System.out.println(l);

当我运行它时,花费了大约11-12秒的时间。

然后我运行了这段代码:

long l = 0;
int i = 0, j = 0;

for(; i < 100; i++)
    for(; j < 1000000000; j++)
        l++;

System.out.println(l);

无论何时运行,这都花费了约100毫秒(0.1秒)的时间。

有没有人知道为什么会有如此大的差异?我的理论是,对于每个'i'的值,内部的for循环都必须重新初始化'j',这使得它需要执行更多的操作,所以需要更长的时间。然而,差异是巨大的(大约多了100倍),而且在其他类似的测试中,却没有发生相同的情况。

如果你想亲自看到,这是我如何计时的:

class Main {
    static long start, end;
    public static void main(String[] args) {
        start();

        long l = 0;
        int i = 0, j = 0;

        for(; i < 100; i++)
            for(; j < 1000000000; j++)
                l++;

        System.out.println(l);

        end();
        print();
    }

    public static void start() {
        start = System.currentTimeMillis();
    }

    public static void end() {
        end = System.currentTimeMillis();
    }

    public static void print() {
        System.out.println((end -  start) + " ms.");
    }
}
英文:

I ran this segment of code: (outer loop runs 100 times, inner loop runs 1 billion times.)

long l = 0;

for(int i = 0; i &lt; 100; i++)
    for(int j = 0; j &lt; 1000000000; j++)
        l++;

System.out.println(l);

This took around 11-12 seconds when I ran it.

Then I ran this segment of code:

long l = 0;
int i = 0, j = 0;

for(; i &lt; 100; i++)
    for(; j &lt; 1000000000; j++)
        l++;

System.out.println(l);

and this took about 100 ms (0.1 seconds) whenever I ran it.

Does anyone have any idea why there's a big difference? My theory is that for every value of 'i', the inner for loop has to initialize j again, which gives it more operations to do, so it makes sense that it takes longer. However, the difference is huge (by about 100 times), and with other similar tests, the same thing doesn't happen.

If you want to see it yourself, this is how I timed it:

class Main {
    static long start, end;
    public static void main(String[] args) {
        start();

        long l = 0;
        int i = 0, j = 0;

        for(; i &lt; 100; i++)
            for(; j &lt; 1000000000; j++)
                l++;

        System.out.println(l);

        end();
        print();
    }

    public static void start() {
        start = System.currentTimeMillis();
    }

    public static void end() {
        end = System.currentTimeMillis();
    }

    public static void print() {
        System.out.println((end -  start) + &quot; ms.&quot;);
    }
}

答案1

得分: 4

第二个函数仅在 I 的第一次迭代中对 j 进行迭代。在那时,j 超过了 for 循环的限制,并且在 i 的下一次迭代中未被重新设置,因此不会再次运行。

英文:

The second function only iterates through j for the first iteration of I. At that point j exceeds the limit of the for loop and is never run again as it is not reset on the next iteration of i

答案2

得分: 1

在你的第一个示例中,内循环在每个i的值上都从0运行到1000000000,因为我们在每个i的值上都将j初始化为0。
在你的第二个示例中,内循环在i = 0时从0运行到1000000000,因为在外部循环的第一次迭代(即i = 0)中,我们只为j初始化为0。

英文:

In your first example, inner loop is running from 0 to 1000000000 for each value of i because we are initializing j=0 for each value of i.
In your second example, inner loop is running from 0 to 1000000000 only for i = 0 because here we are initializing j=0 only for the first iteration of the outer loop (i.e i=0).

答案3

得分: 1

真正的原因在于第二个案例中,循环的运行方式与第一个代码不同。

在第一个代码中,每次进入循环时都会从0开始计算j。
但是在第二个代码中,在第一次迭代中,j将会是10亿。之后,它将始终保持为10亿。这意味着第二个循环的条件每次都不满足。第二个循环将不会运行超过一次。

英文:

Real reason is in second case loop is not running as same as first code.

In first code every time you go inside you start j. With 0
But in second code j will be 1 billion in first iteration. After that It always be 1billoin. Which means second loop condition is failing every time. Second loop will not run more than once.

答案4

得分: 0

两个版本并不是“几乎完全相同的”。实际上,它们是完全不同的。

关键在于它们对 l 打印出不同的值:

/tmp$ java Main1.java
1000000000
12 ms.

/tmp$ java Main2.java
100000000000
857 ms.

显然,一个版本的迭代次数是另一个版本的100倍。@Oli 的回答 解释了其中的原因。


> 我的理论是,对于每个 i 的值,内部的循环需要重新初始化 j,这使得它需要执行更多的操作,所以它花费更长的时间。

不对。这不能解释100倍的性能差异。在我的计算机上,进行100次 int 变量的初始化不可能花费800多毫秒。

真正的解释是你在比较不可比较的计算。

英文:

The two versions are not "almost exactly the same". In fact, they are completely different.

The clue is that they print different values for l:

/tmp$ java Main1.java
1000000000
12 ms.

/tmp$ java Main2.java
100000000000
857 ms.

Clearly one version is doing 100 times more iterations than the other. @Oli's answer explains why.


> My theory is that for every value of i, the inner for loop has to initialize j again, which gives it more operations to do, so it makes sense that it takes longer.

Nope. That would not explain a 100 times performance difference. It is not plausible that 100 initializations of an int variable would take (on my machine) 800+ milliseconds.

The real explanation is that you are comparing computations that are NOT comparable.

答案5

得分: 0

j在它的for循环外被设置为0。在i的下一次迭代中,它没有被重置回0。

英文:

j is set to 0 outside it's for loop. It is never reset back to 0 on i's next iteration.

huangapple
  • 本文由 发表于 2020年4月11日 12:16:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/61152079.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定