【发布时间】:2020-07-25 15:40:10
【问题描述】:
Reflection 被认为在 android 上有点耗时。所以我想知道这样的函数引用:
fun isOdd(x: Int) = x % 2 != 0
val numbers = listOf(1, 2, 3)
println(numbers.filter(::isOdd))
是::isOdd调用是不必要的负担?
不使用它们会更有效吗?
更新:做一些轻量级的指标我做了以下:
class MainActivity : Activity() {
val numbers = listOf(1, 2, 3)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
doRegular()
doReflection()
}
fun isOdd(x: Int) = x % 2 != 0
fun doRegular() {
val start = System.currentTimeMillis()
for (i in 0..999999) {
numbers.filter { it % 2 != 0 }
}
Log.v("myTag", "regular: +${System.currentTimeMillis() - start}")
}
fun doReflection() {
val start = System.currentTimeMillis()
for (i in 0..999999) {
numbers.filter(::isOdd)
}
Log.v("myTag", "reflection: ${System.currentTimeMillis() - start}")
}
}
打印语句结果为:
//*****this was the first attempt before compiler could optimise anything
regular: +577
reflection: 318
//*********
regular: +376
reflection: 327
regular: +593
reflection: 343
regular: +417
reflection: 251
regular: +243
reflection: 238
regular: +241
reflection: 238
regular: +238
reflection: 237
regular: +235
reflection: 247
regular: +237
reflection: 247
regular: +230
reflection: 268
根据这些结果,您会得出什么结论?
更新:有些人问我为什么认为它使用反射。它基于此:
这个stackoverflow answer 似乎说明了它的反射:official doc 的标题以反射作为主要标题:因此我很困惑。
【问题讨论】:
-
是什么让你认为
::isOdd在使用反射? -
作为基准的经验法则,您将其运行 5 倍或更多,并丢弃大的差异。你跑了多少次才得到这样的数字?同样重要的是要知道 jvm 是新鲜的还是已经运行了此代码并有机会通过一些 jit 对其进行优化。
-
@Slaw 我在底部的问题中发表了评论,它基于两个链接
-
也许当 Kotlin 以 JVM 以外的平台为目标时,它真的在后台使用反射?即使函数不是内联,我也希望,当 JVM 是目标平台时,函数引用的工作方式类似于 Java 中的方法引用——不是通过反射。
-
看到最后的迭代收敛到稳定的数字非常有趣。这里可能发生的是常规进行某种优化。如果在 intellij 上尝试将字节码编译为 Java,它可能会为您提供答案。在某些情况下,制作 isodd
inline可能会更快。此外,对于某些基准测试而言,编译器太聪明了,无法按照我们的想法去做。
标签: android kotlin android-reflection