2009-05-28 138 views
12

ØGroovy的大師,Groovy的for循環執行時間

這段代碼運行在1秒左右

for (int i in (1..10000000)) { 
     j = i; 
    } 

,而這其中需要近9秒

for (int i = 1; i < 10000000; i++) { 
     j = i; 
    } 

爲什麼會這樣呢?

回答

9

好的。這是我的理由爲什麼?

如果都轉換腳本字節碼,你會發現,

  1. ForInLoop使用範圍。迭代器用於在每個循環中前進。直接對int(或Integer)進行比較(<)以確定退出條件是否已滿足
  2. ForLoop使用傳統增量,檢查條件並執行操作。爲了檢查條件我< 10000000它使用Groovy的ScriptBytecodeAdapter .compareLessThan。如果你深入挖掘該方法的代碼,你會發現兩側對比取作爲對象,有這麼多東西怎麼回事,鑄造,他們作爲比較對象等

ScriptBytecodeAdapter .compareLessThan - >ScriptBytecodeAdapter .compareTo - >DefaultTypeTransformation .compareTo

有其他類typehandling包特異性實現compareTo方法的數學數據類型,不知道爲什麼在不使用它們,(如果未使用它們)

我懷疑這是第二個循環需要更長時間的原因。 再一次請糾正我,如果我錯了或丟失東西...

+0

這幾乎可以肯定地解釋它。我知道Java風格的for循環爲您提供了更多的靈活性,但它們肯定可以對最基本的(也是最常用的)形式應用一些優化,以便它可以像for..in循環一樣執行?對於從Java或C#來的人來說,這是一個很小的性能陷阱... – Xiaofu 2009-05-30 05:30:53

2

在測試中,確保在採取措施之前先對JVM進行「加熱」,否則可能會觸發平臺中的各種啓動操作(類加載,JIT編譯)。也連續多次運行您的測試。另外,如果您在進行垃圾收集時進行了第二次測試,那可能會產生影響。嘗試運行每個測試100次,並在每次測試後打印出時間,並查看告訴你的內容。

1

如果您可以根據Jim的建議消除啓動時潛在的工件,那麼我會猜測Groovy中的Java風格的for循環沒有像原始的Groovy風格的for循環那麼好實現。它只是在用戶請求後才添加到v1.5中,所以它的實現可能有點後事。

您是否看過爲您的兩個示例生成的字節碼,以查看是否有區別?有一個關於Groovy性能here其中一個評論(從一個「johnchase」)說,這個討論:

不知的區別你看到了相關的用途如何Groovy的數量(元) - 因爲它包裝所有的原語在他們的等價的Java包裝類(int - > Integer)中,我想這會讓事情減慢很多。我會對使用包裝類而不是int進行循環10,000,000次Java代碼的性能感興趣。

所以也許最初的Groovy for循環不會受到這個?只是猜測我的角色。

+0

小福,這些都是好點。我感到困惑的是底部循環應該是更快的,因爲它只處理整數,而不是整數(儘管j的類型沒有指定)。給定順序,頂部循環應該更慢。 – 2009-05-28 15:24:09