Android秒表优化:Kotlin协程小delay及后台计算可行性探讨
Android秒表的协程实现优化与疑问
我正在开发一款每0.1秒刷新一次的Android秒表,初始实现用Kotlin协程的delay(100)控制刷新频率,代码如下:
suspend fun stopwatch() { val startTime = System.currentTimeMillis() var lastSeconds = 0L while (true) { // 控制刷新频率 delay(100) // 计算已流逝时间 val elapsedTime = System.currentTimeMillis() - startTime val seconds = elapsedTime / 1000 // 仅当数值变化时更新UI if (seconds != lastSeconds) { print("${seconds}s\r") lastSeconds = seconds } } }
因为delay的开销比Thread.sleep和handler.post更低,我想提升刷新频率,比如用delay(10)甚至delay(0),让秒表尽可能频繁刷新的同时,不阻塞UI队列执行其他任务。
我写了测试代码对比无delay和带delay(0)的循环耗时,测试代码及结果如下:
suspend fun test() { val iterations = 10_000_000_000 val timeWithNoDelay = measureTimeMillis { var count = 0L while(count < iterations) { count++ } } val timeWithDelay = measureTimeMillis { var count = 0L while(count < iterations){ delay(0) count++ } } println("time: $timeWithNoDelay, $timeWithDelay") println("time per iteration: ${timeWithNoDelay.toDouble() / iterations}, ${timeWithDelay.toDouble() / iterations}") val timeDelay = timeWithDelay - timeWithNoDelay println("delay equivalent to ${timeDelay.toDouble() / timeWithNoDelay} additions") }
测试输出:
time: 3637, 16543 time per iteration: 3.637E-7, 1.6543E-6 delay equivalent to 3.548529007423701 additions
查阅Kotlin协程文档得知,当delay参数非正时会立即返回,测试中的耗时差异来自参数判断逻辑。改用yield替代后,测试结果如下:
time: 414, 32715 iterations: 1000000000, time per iteration: 4.14E-7, 3.2715E-5 delay equivalent to 78.02173913043478 additions
另外我还有个疑问:如果每秒仅100次迭代(耗时约7ms),有没有必要把秒表的计算逻辑通过withContext(Dispatchers.Default)放到后台线程执行?相关测试代码及结果如下:
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.runBlocking import kotlinx.coroutines.yield import kotlin.system.measureTimeMillis fun test(iterations: Long){ val startTime = 0 val formattedTime = MutableStateFlow("") val time = measureTimeMillis { for (i in 0..iterations) { val elapsedTime = System.currentTimeMillis() - startTime formattedTime.value = "$elapsedTime ms" } } println("iterations: $iterations, time: $time, time per iteration: ${time.toDouble()/iterations}") runBlocking { val startTime = 0 val formattedTime = MutableStateFlow("") val timeWithDelay = measureTimeMillis { for (i in 0..iterations) { val elapsedTime = System.currentTimeMillis() - startTime formattedTime.value = "$elapsedTime ms" yield() // 等效于delay(0) } } println("iterations: $iterations, timeWithDelay: $timeWithDelay, time per iteration: ${timeWithDelay.toDouble()/iterations}") } } fun main(){ test(100) }
测试输出:
iterations: 100, time: 6, time per iteration: 0.06 iterations: 100, timeWithDelay: 7, time per iteration: 0.07
内容的提问来源于stack exchange,提问作者BPDev
相关产品推荐
相关产品推荐

