有人說Scala對於理解其實很慢。我得到的理由是,由於Java的限制,對於理解(比如「reduce」,下面使用)需要生成一個臨時對象,每次迭代以調用傳入的函數。與FOR循環相比,爲什麼Scala「for循環理解」非常慢?
IS .. 。這是真的?下面的測試似乎證實了這一點,但我不完全明白爲什麼會出現這種情況。
這可能對「lambdas」或匿名函數有意義,但不適用於非匿名函數。
在我的測試中,我運行了針對list.reduce的循環(見下面的代碼),並發現它們的速度是以前的兩倍,即使每次迭代都調用完全相同的函數以減少!
我覺得這非常不直觀(一旦認爲Scala庫會被精心地創建爲儘可能優化)。
在測試I放在一起,我跑的相同環路(總結編號1〜一百萬,而不論溢出的)五種不同的方法:
- for循環值的陣列之上
- for循環,而是調用一個函數,而不是在線算術
- for循環,創建一個包含除了功能
- list.reduce一個對象,我傳遞一個匿名函數
- list.reduce,傳遞對象的成員函數
結果如下: 測試:最小/最大/平均值(毫秒)
1. 27/157/64.78
2. 27/192/65.77 <--- note the similarity between tests 1,2 and 4,5
3. 139/313/202.58
4. 63/342/150.18
5. 63/341/149.99
如可以看到的,在「用於理解」版本的「量級對於每個實例都是新的「,這意味着實際上可以爲匿名和非匿名函數版本執行」新「。
方法:將下面的代碼(已刪除測試調用)編譯爲單個.jar文件,以確保所有版本都運行相同的庫代碼。每次迭代中的每個測試都在新的JVM中調用(即每次測試的scala -cp ...)以消除堆大小問題。
class t(val i: Int) {
def summit(j: Int) = j + i
}
object bar {
val biglist:List[Int] = (1 to 1000000).toList
def summit(i: Int, j:Int) = i+j
// Simple for loop
def forloop: Int = {
var result: Int = 0
for(i <- biglist) {
result += i
}
result
}
// For loop with a function instead of inline math
def forloop2: Int = {
var result: Int = 0
for(i <- biglist) {
result = summit(result,i)
}
result
}
// for loop with a generated object PER iteration
def forloop3: Int = {
var result: Int = 0
for(i <- biglist) {
val t = new t(result)
result = t.summit(i)
}
result
}
// list.reduce with an anonymous function passed in
def anonymousfunc: Int = {
biglist.reduce((i,j) => {i+j})
}
// list.reduce with a named function
def realfunc: Int = {
biglist.reduce(summit)
}
// test calling code excised for brevity. One example given:
args(0) match {
case "1" => {
val start = System.currentTimeMillis()
forloop
val end = System.currentTimeMillis()
println("for="+(end - start))
}
...
}
'.reduce'與「for comprehensions」無關 –
作爲一個方面說明,scala編譯器插件旨在消除常見情況下的這種開銷:https://code.google.com/p/scalacl /維基/ ScalaCLPlugin。雖然我沒有嘗試過。 –
實際上,你的前3個測試使用了for-comprehensions,並且你正在比較那些與reduce的時間。 –