在java中我通常做一個for循環類似以下內容:是++我真的比i ++中的for循環更快嗎?
for (int i = 0; i < max; i++) {
something
}
但最近有同事鍵入了這樣:
for (int i = 0; i < max; ++i) {
something
}
他說,後者會更快。真的嗎?
在java中我通常做一個for循環類似以下內容:是++我真的比i ++中的for循環更快嗎?
for (int i = 0; i < max; i++) {
something
}
但最近有同事鍵入了這樣:
for (int i = 0; i < max; ++i) {
something
}
他說,後者會更快。真的嗎?
不,這是不正確的。您可以通過對每個循環進行大量迭代計時來衡量性能,但我相當肯定他們會一樣。
神話來自C,其中++i
被認爲比i++
快,因爲前者可以通過增加我然後返回它來實現。後者可以通過將i的值複製到臨時變量來實現,遞增i,然後返回臨時變量。第一個版本不需要製作臨時版本,許多人認爲它更快。但是,如果表達式用作陳述,則現代C編譯器可以優化臨時副本,以便在實踐中不會有任何區別。
即使是這樣,我非常懷疑,你的同事真的應該花更多時間學習,而不是如何優化循環表達式。
對於任何具有合理能力的優化器,它們將完全相同。如果您不確定,請查看輸出字節碼或配置文件。
它不會更快。編譯器和帶有JIT的JVM將使這種微不足道的差異變得更小。
您可以使用常用的循環優化技術來獲得速度優勢,如展開(如果適用)。
即使它會更快,在HotSpot的日子裏沒人在乎。 JIT所做的第一件事是刪除所有由javac製作的優化。之後,所有內容都留給JIT來加快速度。
在Java中不應該有差別 - 任何現代編譯器*應該產生在這兩種情況下相同的字節碼(只是一個iinc
),因爲增量表達式的結果沒有被使用直接。
還有第三種選擇,仍然是相同的字節碼*:
for (int i = 0; i < max; i += 1) {
something
}
*與Eclipse的編譯器測試
沒有也不會有什麼不同。
這是來自C++,但即使如此,在這種情況下也沒有任何區別。 哪裏有差異是我在哪裏是一個對象。我必須爲該對象創建一個額外的副本,因爲它必須返回該項目的原始未更改值,而++我可以返回已更改的對象以便保存副本。
在使用用戶定義的對象的C++中,副本的成本可能很大,所以它肯定值得記住。因爲這個人也傾向於將它用於int變量,因爲它無論如何都是一樣的...
反編譯「javap -c YourClassName」並查看結果並由此決定。通過這種方式,您可以看到編譯器在每種情況下實際執行的操作,而不是您認爲它的作用。這樣你也可以看到爲什麼一種方式比另一種更快。
這個問題需要一些Java字節碼。請看下面的代碼:
public class PostPre {
public static void main(String args[]) {
int n = 5;
loop1(n);
loop2(n);
}
public static void loop1(int n) {
for (int i = 0; i < n; i++) {}
}
public static void loop2(int n) {
for (int i = 0; i < n; ++i) {}
}
}
現在編譯和拆解:
$ javac PostPre.java; javap -c PostPre.class
Compiled from "PostPre.java"
public class PostPre {
public PostPre();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_5
1: istore_1
2: iload_1
3: invokestatic #2 // Method loop1:(I)V
6: iload_1
7: invokestatic #3 // Method loop2:(I)V
10: return
public static void loop1(int);
Code:
0: iconst_0
1: istore_1
2: iload_1
3: iload_0
4: if_icmpge 13
7: iinc 1, 1
10: goto 2
13: return
public static void loop2(int);
Code:
0: iconst_0
1: istore_1
2: iload_1
3: iload_0
4: if_icmpge 13
7: iinc 1, 1
10: goto 2
13: return
}
loop1()
和loop2()
具有相同的字節碼。
在您的環境試試這個
public class IsOptmized {
public static void main(String[] args) {
long foo; //make sure the value of i is used inside the loop
long now = 0;
long prefix = 0;
long postfix = 0;
for (;;) {
foo = 0;
now = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
foo += i;
}
postfix = System.currentTimeMillis() - now;
foo = 0;
now = System.currentTimeMillis();
for (int i = 0; i < 1000000000; ++i) {
foo += i;
}
prefix = System.currentTimeMillis() - now;
System.out.println("i++ " + postfix + " ++i " + prefix + " foo " + foo);
}
}
}
礦給我
i++ 1690 ++i 1610 foo 499999999500000000
i++ 1701 ++i 1610 foo 499999999500000000
i++ 1701 ++i 1600 foo 499999999500000000
i++ 1701 ++i 1610 foo 499999999500000000
i++ 1701 ++i 1611 foo 499999999500000000
i++ 1701 ++i 1610 foo 499999999500000000
i++ 1691 ++i 1610 foo 499999999500000000
i++ 1701 ++i 1600 foo 499999999500000000
i++ 1701 ++i 1610 foo 499999999500000000
i++ 1691 ++i 1610 foo 499999999500000000
i++ 1701 ++i 1610 foo 499999999500000000
i++ 1691 ++i 1610 foo 499999999500000000
i++ 1701 ++i 1610 foo 499999999500000000
i++ 1701 ++i 1610 foo 499999999500000000
i++ 1701 ++i 1610 foo 499999999500000000
i++ 1692 ++i 1610 foo 499999999500000000
i++ 1701 ++i 1610 foo 499999999500000000
i++ 1691 ++i 1610 foo 499999999500000000
因此,即使它沒有那麼多,我asume是有區別的
在Java中有沒有這種差異。 Java機器編碼代碼,無論您編寫++ i還是i ++,它都將轉換爲字節代碼以完全相同的指令集。
但是在C/C++中有一個巨大的差異,如果你沒有使用任何優化標誌,那麼你的循環可以慢3倍。
使用類似-O/-O3的優化標誌將強制編譯器使輸出asembly代碼更簡單(在大多數情況下),因此更快(大多數情況下)。
我想你會有麻煩來衡量當代差異。更好的結果通常是通過優化循環中的零件*來實現的) – 2011-01-28 18:30:56
它可能是,但很少,甚至從來沒有注意到。像這樣的微觀優化是完全沒有用的。 – 2011-01-28 18:31:21
@PeeHaa:兩個循環都運行相同數量的循環。我嘗試了最大= 10,他們都從0到9爲我。 – Mnementh 2011-01-28 18:36:19