Медленный диапазон для каждого в Котлине - PullRequest
0 голосов
/ 20 октября 2018

Я использовал следующий код для измерения производительности различных синтаксических конструкций в Kotlin

fun time(what: String, body: () -> Int) {
    val start = System.currentTimeMillis()
    var sum = 0

    repeat(10) {
        sum += body()
    }

    val end = System.currentTimeMillis()

    println("$what: ${(end - start) / 10}")
}

val n = 200000000
val rand = Random()
val arr = IntArray(n) { rand.nextInt() }

time("for in range") {
    var sum = 0
    for (i in (0 until n))
        sum += arr[i]
    sum
}

time("for in collection") {
    var sum = 0
    for (x in arr)
        sum += x
    sum
}

time("forEach") {
    var sum = 0
    arr.forEach { sum += it }
    sum
}

time("range forEach") {
    var sum = 0
    (0 until n).forEach { sum += arr[it] }
    sum
}

time("sum") {
    arr.sum()
}

И вот результат, который я получил:

для диапазона: 84
for in collection: 83
forEach: 86
range forEach: 294
sum: 83

Итак, мой вопрос: почему диапазон forEach намного медленнее, чем другие синтаксические конструкции?
Мне кажется, что компилятор может генерировать одинаковый байт-код во всех случаях (но не в случае "range forEach")

Ответы [ 2 ]

0 голосов
/ 20 октября 2018

Из документации:

Цикл for по диапазону или массиву компилируется в цикл на основе индекса, который не создает объект итератора.

forEach, как вы можете видеть на https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/for-each.html, имеет специальный корпус для массивов, но имеет одну реализацию для всех Iterable s, поэтому ему необходимо создать итератор.

0 голосов
/ 20 октября 2018

Наиболее интересное сравнение, вероятно, между этими двумя случаями:

Случай A: занимает 86 мс

time("forEach") {
    var sum = 0
    arr.forEach { sum += it }
    sum
}

Случай B: занимает 294 мс

time("range forEach") {
    var sum = 0
    (0 until n).forEach { sum += arr[it] }
    sum
}

В то время как случай A вызывает IntArray.forEach(...), случай B вызывает Iterable<T>.forEach(...) - это два разных вызова.

Я думаю, компилятор Kotlin знает, как оптимизировать IntArray.forEach(...), но не Iterable<T>.forEach(...).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...