在我的 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/