2011-01-28 32 views
29

在java中我通常做一個for循環類似以下內容:是++我真的比i ++中的for循環更快嗎?

for (int i = 0; i < max; i++) { 
    something 
} 

但最近有同事鍵入了這樣:

for (int i = 0; i < max; ++i) { 
    something 
} 

他說,後者會更快。真的嗎?

+6

我想你會有麻煩來衡量當代差異。更好的結果通常是通過優化循環中的零件*來實現的) – 2011-01-28 18:30:56

+2

它可能是,但很少,甚至從來沒有注意到。像這樣的微觀優化是完全沒有用的。 – 2011-01-28 18:31:21

+1

@PeeHaa:兩個循環都運行相同數量的循環。我嘗試了最大= 10,他們都從0到9爲我。 – Mnementh 2011-01-28 18:36:19

回答

53

不,這是不正確的。您可以通過對每個循環進行大量迭代計時來衡量性能,但我相當肯定他們會一樣。

神話來自C,其中++i被認爲比i++快,因爲前者可以通過增加我然後返回它來實現。後者可以通過將i的值複製到臨時變量來實現,遞增i,然後返回臨時變量。第一個版本不需要製作臨時版本,許多人認爲它更快。但是,如果表達式用作陳述,則現代C編譯器可以優化臨時副本,以便在實踐中不會有任何區別。

5

即使是這樣,我非常懷疑,你的同事真的應該花更多時間學習,而不是如何優化循環表達式。

9

對於任何具有合理能力的優化器,它們將完全相同。如果您不確定,請查看輸出字節碼或配置文件。

1

它不會更快。編譯器和帶有JIT的JVM將使這種微不足道的差異變得更小。

您可以使用常用的循環優化技術來獲得速度優勢,如展開(如果適用)。

-2

即使它會更快,在HotSpot的日子裏沒人在乎。 JIT所做的第一件事是刪除所有由javac製作的優化。之後,所有內容都留給JIT來加快速度。

0

在Java中不應該有差別 - 任何現代編譯器*應該產生在這兩種情況下相同的字節碼(只是一個iinc),因爲增量表達式的結果沒有被使用直接
還有第三種選擇,仍然是相同的字節碼*

for (int i = 0; i < max; i += 1) { 
    something 
} 

*與Eclipse的編譯器測試

1

沒有也不會有什麼不同。

這是來自C++,但即使如此,在這種情況下也沒有任何區別。 哪裏有差異是我在哪裏是一個對象。我必須爲該對象創建一個額外的副本,因爲它必須返回該項目的原始未更改值,而++我可以返回已更改的對象以便保存副本。

在使用用戶定義的對象的C++中,副本的成本可能很大,所以它肯定值得記住。因爲這個人也傾向於將它用於int變量,因爲它無論如何都是一樣的...

1

反編譯「javap -c YourClassName」並查看結果並由此決定。通過這種方式,您可以看到編譯器在每種情況下實際執行的操作,而不是您認爲它的作用。這樣你也可以看到爲什麼一種方式比另一種更快。

34

這個問題需要一些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()具有相同的字節碼。

2

在您的環境試試這個

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是有區別的

0

在Java中有沒有這種差異。 Java機器編碼代碼,無論您編寫++ i還是i ++,它都將轉換爲字節代碼以完全相同的指令集。

但是在C/C++中有一個巨大的差異,如果你沒有使用任何優化標誌,那麼你的循環可以慢3倍。

使用類似-O/-O3的優化標誌將強制編譯器使輸出asembly代碼更簡單(在大多數情況下),因此更快(大多數情況下)。