2013-02-04 193 views
6

什麼是for循環的Java for循環性能

這更好:

for(int i = 0; i<someMethod(); i++) 
{//some code 
} 

或:

int a = someMethod(); 
for(int i = 0; i<a; i++) 
{//some code 
} 

讓我們只說的someMethod()回報的東西大。

第一種方法將執行的someMethod()在每個循環從而降低速度,第二速度更快,但是,讓我們說,有很多應用類似的循環,從而宣告一個可變VILL消耗更多的存儲器。

那麼有什麼更好,還是我只是在愚蠢地思考。

+0

在你的例子'a'是局部變量,所以它只在執行位於定義的塊內時才消耗內存。 –

回答

11

第二個更好 - 假設someMethod()沒有side effects
它實際上緩存由someMethod()計算的值 - 所以你不必重新計算它(假設它是一個相對廣泛的操作)。

如果確實如此(有副作用) - 兩個代碼卡扣並不等同 - 你應該做的是正確的

關於「爲可變大小」 - 它不反正的someMethod()需要返回值計算前無論如何存儲在一些中間臨時變量的問題(即使它是不是這種情況,一個整數的大小可以忽略不計)。

P.S.
在某些情況下,編譯器/ JIT優化器可能會將第一個代碼優化到第二個代碼中,假設當然沒有副作用。

+0

謝謝,非常好的解釋 – pedja

+1

+1指向'側面效應' – exexzian

4

如果有疑問,測試。使用分析器。測量。

+0

寫microbenchmark是如此困難,我總是提醒。除非您已準備好檢查生成的彙編程序並知道JVM如何優化它是一項艱鉅的任務 – bestsss

4

假設迭代順序是不相關的,也假設你真的想納米優化你的代碼,你可以這樣做:

for (int i=someMethod(); i-->0;) { 
    //some code 
} 

但是附加的局部變量(您a)不這樣的負擔。在實踐中,這與你的第二個版本沒有多大區別。

+2

您是納米優化的代價是可讀性......沒有證據表明更易讀(明顯)優化的版本不會只是一樣快。 –

+0

嗯......我不認爲它的可讀性不好,至少在我展示的代碼中。我認爲不利的一面是,讀者和維護人員通常期待我的成長,特別是當你迭代一個列表時。 –

+0

@dstroy - 查看我的答案,瞭解我在說什麼。 –

2

這實際上取決於生成someMethod()的輸出需要多長時間。內存使用情況也是一樣的,因爲someMethod()首先必須生成輸出並存儲它。第二種方法是保護你的CPU不會在每個循環中計算相同的輸出,並且不應該佔用更多的內存。所以第二個更好。

2

我不認爲變量a的內存消耗是一個問題,因爲它是一個int,並且需要在64位機器上有192位。所以我更喜歡第二種選擇,因爲它的執行效率更好。

3

如果您不需要循環後這個變量,有簡單的方法來裏面隱藏:

for (int count = someMethod(), i = 0; i < count; i++) 
{ 
    // some code 
} 
0

如果您需要優化這一點,那麼這是乾淨的/明顯的方式做到這一點:

int a = someMethod(); 
for (int i = 0; i < a; i++) { 
    //some code 
} 

替代形式通過@dystroy

for (int i=someMethod(); i-->0;) { 
    //some code 
} 

建議......有三個問題。

  • 他正在反方向迭代。

  • 該迭代是非慣用的,因此可讀性較差。特別是如果您忽略Java風格指南,並且不要將空白處放在您應該使用的位置。

  • 沒有證據表明代碼實際上比更慣用的版本更快......尤其是一旦JIT編譯器對它們進行了優化。 (即使少閱讀的版本速度更快,差別很可能是微不足道的。)

在另一方面,如果someMethod()是昂貴的(因爲你假定),則「吊裝」的號召,使其只做一次可能是值得的。

+0

第一個變體[在循環中調用]必須有足夠的'內聯預算'左側內聯someMethod(),尤其是,如果它可以被覆蓋。沒有內聯意味着多次調用,而不是展開循環+可能的範圍檢查。 – bestsss

1

關於循環優化最重要的部分是允許JVM展開循環。要在第一個變體中這樣做,它必須能夠將呼叫內聯到someMethod()。內聯有一些預算,它可以在某個時候被搗毀。如果someMethod()足夠長,JVM可能會決定它不喜歡內聯。

第二個變體更有用(對JIT編譯器),並可能更好地工作。

我的放下循環的方法是: for (int i=0, max=someMethod(); i<max; i++){...}

max不污染的代碼,你確保的someMethod()的多次調用無副作用,它的結構緊湊(單排)