android - 为什么 List<Float>.toFloatArray 与填充 FloatArray 相比这么慢? (漏洞?)

标签 android arrays list opengl-es kotlin

在我的 Android 手机应用程序中有许多大型 float 列表(100000+)。为了将它们与 OpenGl 一起使用,列表被转换为 FloatArrays,然后转换为字节缓冲区。我遇到了性能问题,几个小时后,Kotlin .toFloatArray() 函数似乎非常慢。

在我的三星 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)

用值填充 float 组很快,用 float 填充列表慢 7.4 倍。

然而,通过标准函数 List.toFoatArray() 将 List 转换为 float 组比简单地填充数组慢 6.1 倍,也比简单地填充数组慢 2.4 倍遍历列表。它几乎和用 float 填充空列表一样慢!

我希望转换时间更接近简单地填充数组的时间?

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

}
}

最佳答案

这是我的代码,它试图将两种转换方式置于比您的测试更平等的基础上:

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 并且不能使用索引迭代。

关于android - 为什么 List<Float>.toFloatArray 与填充 FloatArray 相比这么慢? (漏洞?),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50213876/

相关文章:

Android:如何根据屏幕设置标题的高度或宽度

java - ArrayAdapter NullPointerException 尝试在空对象引用上调用虚拟方法

arrays - 如何初始化@Binding SwiftUi

arrays - 将 CSV 文件的内容加载到数组而不打开文件

python - 从列表中提取某些值

java - Android Sqlite 仅更新第一行

android - 我们可以将共享偏好存储在 SD 卡上吗

c++ - 在堆上分配 bitset<N> 数组

python - 使用 lambda 访问列表中字典的值

python - pyplot : Plotting [Lists of [(Lists of Tuples)]]