内联函数
- 潜在性能瓶颈
- 代码膨胀:如果内联函数体较大,并且在多处被调用,会导致生成的字节码体积增大,因为内联函数会将代码直接插入到调用处,增加了整体代码量。
- 递归调用问题:内联函数不支持递归调用优化,因为递归调用会导致代码无限膨胀。
- 性能优化策略
- 控制函数体大小:确保内联函数体足够小,仅包含简单的逻辑。如果函数体复杂,考虑将其拆分成更小的内联函数或者普通函数。
- 避免递归内联:对于递归逻辑,使用普通函数实现。
- 示例代码
// 简单的内联函数示例,用于安全调用可空对象的方法
inline fun <T, R> T?.safeCall(block: (T) -> R): R? {
if (this != null) {
return block(this)
}
return null
}
// 使用示例
val str: String? = "Hello"
val length = str.safeCall { it.length }
println(length)
协程
- 潜在性能瓶颈
- 上下文切换开销:协程在挂起和恢复时会发生上下文切换,如果频繁进行挂起操作,会带来额外的性能开销。例如在一个协程中多次调用
delay
函数,每次 delay
都会导致协程挂起,增加上下文切换次数。
- 资源竞争:当多个协程访问共享资源时,如果没有正确的同步机制,可能会出现资源竞争问题,影响性能甚至导致数据不一致。
- 性能优化策略
- 减少不必要的挂起:尽量合并挂起操作,避免在循环中频繁挂起。例如,可以将多个
delay
操作合并成一个较长时间的 delay
。
- 合理使用同步机制:对于共享资源,使用
Mutex
等同步工具来确保线程安全。例如,多个协程访问一个可变的共享集合时,使用 Mutex
来保护对集合的操作。
- 示例代码
import kotlinx.coroutines.*
// 减少不必要挂起示例
fun main() = runBlocking {
val startTime = System.currentTimeMillis()
// 不推荐,多次挂起
repeat(10) {
delay(100)
}
val endTime1 = System.currentTimeMillis()
println("多次挂起耗时: ${endTime1 - startTime} ms")
val startTime2 = System.currentTimeMillis()
// 推荐,合并挂起
delay(1000)
val endTime2 = System.currentTimeMillis()
println("合并挂起耗时: ${endTime2 - startTime2} ms")
}
// 资源竞争示例,使用Mutex
val mutex = Mutex()
val sharedList = mutableListOf<Int>()
fun main2() = runBlocking {
launch {
mutex.lock()
try {
sharedList.add(1)
} finally {
mutex.unlock()
}
}
launch {
mutex.lock()
try {
sharedList.add(2)
} finally {
mutex.unlock()
}
}
delay(100)
println(sharedList)
}