2012-08-03 41 views
4

例如:Java爲什麼不在循環中存儲條件的值?

for(int i = 0; i < 20 * 40 * 60 * 80; i++){ ... } 

相比:

for(int i = 0; i < 3840000; i++){ ... } 

第一個循環的運行速度比第二慢得多(做了一些時間的試驗),即使有條件的價值永遠不會改變任何整個迭代階段。當然,用這種方法會有所不同,因爲這個值可能會改變(即使它可能不應該)。我只是想知道爲什麼Java不會緩存/臨時存儲這個值。

long fact10 = factorial(10); 
for(long n = 0; n < fact10; n++) vs for(long n = 0; n < factorial(10); n++) 
+0

cache/temp,是不是依賴於實現?我想原因可能是,第一個是表達。 – kosa 2012-08-03 02:53:16

+4

你的第二個例子與你的第一個例子完全不同。您的第一個示例使用常量值,第二個示例使用方法調用。就編譯器所知,連續調用'factorial(10)'可能會返回不同的結果。 Java中沒有內置[memoization](http://en.wikipedia.org/wiki/Memoization)機制。 – Jeffrey 2012-08-03 02:54:45

+0

另外,就第一個例子而言,你是否在同一個jvm運行中運行它們?如果是這樣,你是否首先加熱一切?執行這兩個測試的順序很重要,因爲jvm的開銷和初始化幾乎肯定會降低第一個測試的速度。 – Matt 2012-08-03 03:34:25

回答

6

Java不能做第二次優化,因爲它不知道factorial沒有副作用。就第一個基準測試而言,我確信這是某種錯誤:Java編譯器在編譯時計算常量表達式的結果,所以前兩個循環是等價的。

0

從理論上講(雖然我已經受夠了這種糟糕的成功),你可以改變環路你的「<」語句的結果。

例如:

int x = 1; 

for(int i = 0; i < x * 2; i++) 
{ 
    if(x < 10) 
    x += i; 
} 

我不知道確切的原因,它的計算不考慮值的每一次,但每次迭代的情況下,變量都存在時它總是重新計算數學。

2

我覺得你的微基準是有缺陷的,大部分都是。

標杆正確是一種藝術形式。 Oracle JVM有一個即時編譯器(JIT),我相信如果你運行這個足夠長的時間,你會發現它在啓發式地決定這些值永不改變之後最終會加速。

0

我認爲它可以,每次檢查條件。所以你可以這樣實現:

 synchronized (veryBigList) { 
      for (Iterator iter = veryBigList.iterator();iter.hasNext();) { 
       Object o = iter.next(); 
       //Do something 
      } 
     } 

請注意,某些列表實現具有不同的性能。 我認爲(不知道現在),

的ArrayListsize()非常快,但在add()慢如果 underlaying的陣列已經被擴展。 LinkedList的size(), 緩慢但add()

非常快,我更喜歡這樣的解決方案:

synchronized (veryBigList) { 
     for (int i = 0, l = veryBigList.size(); i < l; i++) { 
      //Do something 
     } 
    } 
+0

'LinkedList'對於'size()'實際上是O(1)。你應該更喜歡使用迭代器。 – EJP 2012-08-03 07:47:32

+0

除非你需要一個索引指針。 – rtheunissen 2012-08-03 09:03:44

+0

我認爲我們寫的是不同的東西。我用迭代器的例子只是解釋我如何使用for循環來。我認爲sser dasblinkenlicht說的是正確的。我對不同List實現的評論只是一個提示,因爲許多硬編碼器不知道這些問題。 – Mirko 2012-08-03 12:13:18

0

你有循環裏面是什麼,因爲我寫了一個小程序和所花費的時間是在幾乎相同這兩種情況。所以這取決於你在第一次和第二次循環中的內容。

public static void main(String[] args) { 
     long startTime = System.currentTimeMillis(); 
     int x = 0; 
     for (int i = 0; i < 500000000 ; i++) { 
      x++; 
     } 
     long endTime = System.currentTimeMillis(); 
     long totalTime1 = endTime - startTime; 
     System.out.println("First time " + totalTime1); 

     startTime = System.currentTimeMillis(); 
     int j = 0; 
     for (int i = 0; i < 50 * 100 * 10 * 10000 ; i++) { 
      j++; 
     } 
     endTime = System.currentTimeMillis(); 
     long totalTime2 = endTime - startTime; 
     System.out.println("Second time " + totalTime2); 


     System.out.println("First Loop " + totalTime1 + " Second Loop " + totalTime2); 
}