Почему List <Float>.toFloatArray такой медленный по сравнению с заполнением FloatArray? (Ошибка?) - PullRequest
0 голосов
/ 07 мая 2018

В моем приложении для телефона Android есть много больших списков поплавков (100000+). Чтобы использовать их с OpenGl, списки преобразуются в FloatArrays, а затем в байтовые буферы. У меня возникли проблемы с производительностью, и спустя много часов кажется, что функция Kotlin .toFloatArray () работает очень медленно.

Некоторые результаты теста на моем телефоне Samsung Galaxy:

                        elapsed time(msec)  time/float(microsec)        
                            max min  avg 
fillFloatArray               70  39  59,7      6.0
fillFloatList               472 357 444,1     44.4
convertListToArrayLooping   165 101 155,2     15.5
convertWithToFloatArray     388 318 367,3     36.7

Number of floats    10000               
runs                   10
(the average time / float is the same for a list of 100000 floats)

Заполнение floatarray значениями происходит быстро, а заполнение списка с помощью float - в 7,4 раза медленнее.

Однако преобразование List в floatarray с помощью стандартной функции List.toFoatArray () в 6,1 раза медленнее, чем простое заполнение массива, также 2,4 раза медленнее , чем циклическое повторение список. Это почти так же медленно, как заполнение пустого Списка с помощью Floats!

Я ожидал, что время преобразования будет ближе ко времени простого заполнения массива?

Имеет ли смысл выполнение .toFloatArray ()? И какой самый быстрый или, по крайней мере, более быстрый способ преобразования списка в байтбуфер?

Под небольшой тестовой программой, для справки.

class PlayGround {
private val stopwatch = Timing()

private val arraylist: MutableList<Float> = arrayListOf()
private val fillFloatArray = Results()
private val fillFloatList = Results()
private val convertListToArrayLooping = Results()
private val convertWithToFloatArray = Results()

fun checkSpeed () {
    for (i in 0 until 10) {     // do the timing ten times to get an average
        // filling a floatarray with 10000 floats
        stopwatch.start()
        var array = FloatArray(10000, { it * 1f })
        fillFloatArray.add(stopwatch.stop())

        // filling a list with 10000 floats
        stopwatch.start()
        for (i in 0 until 10000) {
            arraylist.add(i * 1f)
        }
        fillFloatList.add(stopwatch.stop())

        // converting the fulllist to a floatarray by looping
        stopwatch.start()
        for (i in 0 until arraylist.size) {
            array[i] = arraylist[i]
        }
        convertListToArrayLooping.add(stopwatch.stop())

        // converting the fullist to a floatarray with toFloatArray
        stopwatch.start()
        array = arraylist.toFloatArray()
        convertWithToFloatArray.add(stopwatch.stop())
        arraylist.clear()
    }
}

private class Results {
    private var max = Long.MIN_VALUE
    private var min = Long.MAX_VALUE
    private var sum = 0L
    private var avg = 0L
    var measurePoints: MutableList<Long> = arrayListOf()

    fun add (msrp: Long) {
        measurePoints.add(msrp)
        if (msrp > max) max = msrp
        if (msrp < min) min = msrp
        sum += msrp
        avg = sum / measurePoints.size
    }

    fun clear() {
        measurePoints.clear()
        max = Long.MIN_VALUE
        min = Long.MAX_VALUE
        sum = 0L
        avg = 0L
    }

    fun max(): Long { return max}
    fun min(): Long { return min}
    fun sum(): Long { return sum}
    fun avg(): Long { return avg}

}
}

1 Ответ

0 голосов
/ 07 мая 2018

Вот мой код, он пытается поставить два способа преобразования на более равные условия, чем ваши тесты:

import kotlin.system.measureTimeMillis

const val PROBLEM_SIZE = 1_000_000

fun main(args: Array<String>) {
    val array = FloatArray(PROBLEM_SIZE, { it * 1f })
    val list: List<Float> = array.map { it }

    println("warmup")
    (1..20).forEach {
            list.myToFloatArray()
            list.toFloatArray()
    }

    println("list.toFloatArray " + (1..10).map {
        gc()
        measureTimeMillis {
            list.myToFloatArray()
        }
    }.average())

    println("collection.toFloatArray " + (1..10).map {
        gc()
        measureTimeMillis {
            list.toFloatArray()
        }
    }.average())
}

fun List<Float>.myToFloatArray(): FloatArray {
    val result = FloatArray(size)
    for (index in 0 until size)
        result[index] = this[index]
    return result
}

fun gc() {
    System.gc()
    System.gc()
}

Это типичный результат

list.toFloatArray 3.4
collection.toFloatArray 5.2

Во-первых, разница менее выражена, чем в ваших тестах, а во-вторых, стандартная функция - Collection.toFloatArray и не может использовать индексированную итерацию.

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