Почему Scala «для понимания циклов» настолько медленный по сравнению с циклами FOR?

Было сказано, что Scala для понимания на самом деле довольно медленно. Причина, по которой мне было дано, состояла в том, что из-за ограничений Java для понимания (например, «redu», используемого ниже) необходимо генерировать временный объект с каждой итерацией для вызова переданной функции.

ЭТО ПРАВДА? Тесты ниже, кажется, подтверждают это, но я не совсем понимаю, почему это так.

Это может иметь смысл для «лямбд» или анонимных функций, но не для неанонимных функций.

В моем тесте я запустил циклы для list.reduce (см. Код ниже) и обнаружил, что они работают в два раза быстрее, даже если каждая итерация вызывает одну и ту же функцию, которая была передана для сокращения!

Я нахожу это удивительно нелогичным (когда-то казалось бы, что библиотека Scala была бы тщательно создана, чтобы быть максимально оптимальной).

В тесте, который я собрал, я запустил один и тот же цикл (суммируя числа от 1 до миллиона, независимо от переполнения) пятью различными способами:

цикл по массиву значенийдля цикла, но вызывая функцию вместо встроенной арифметикицикл 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))
                    }
         ...
}

Ответы на вопрос(1)

Ваш ответ на вопрос