Por que o Scala “for loop comprehensions” é tão lento comparado aos loops FOR?

Foi dito que o Scala For comprehensions é realmente muito lento. A razão que me foi dada foi que, devido a uma limitação de Java, para as compreensões (como "reduzir", usado abaixo) precisa gerar um objeto temporário com cada iteração para chamar a função passada.

ISSO É VERDADE? Os testes abaixo parecem confirmar isso, mas eu não entendo completamente porque este é o caso.

Isso pode fazer sentido para "lambdas" ou funções anônimas, mas não para funções não anônimas.

No meu teste, eu corri para loops contra list.reduce (veja o código abaixo), e descobri que eles são mais de duas vezes mais rápidos, mesmo quando cada iteração chamou exatamente a mesma função que foi passada para reduzir!

Acho isso surpreendentemente contra-intuitivo (uma vez pensaria que a biblioteca Scala teria sido cuidadosamente criada para ser o mais ideal possível).

Em um teste que realizei, executei o mesmo loop (some os números de 1 a um milhão, independentemente do estouro) de cinco maneiras diferentes:

para loop sobre a matriz de valorespara loop, mas chamando uma função em vez de aritmética inlinefor loop, criando um objeto que contém uma função de adiçãolist.reduce, passando uma função anônimalist.reduce, passando em uma função de membro de objeto

Os resultados foram os seguintes: teste: min / max / average (milissegundos)

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

Como pode ser visto, as versões "para compreensão" estão na ordem de "para com novo para cada instância", implicando que um "novo" pode de fato ser executado para as versões de função anônima e não-anônima.

Metodologia: o código abaixo (chamada de teste removida) foi compilado em um único arquivo .jar para garantir que todas as versões tenham o mesmo código de biblioteca. Cada teste em cada iteração foi chamado em uma nova JVM (ou seja, scala -cp ... para cada teste) para remover problemas de tamanho de heap.

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))
                    }
         ...
}

questionAnswers(1)

yourAnswerToTheQuestion