背景

多测线雷达图加载,原来用 ExecutorService + Thread:每条测线一个任务,结果通过回调或 Future 收集。线程数靠拍脑袋,取消靠一个 volatile 标志位,异常处理各写各的,并行度也控制不好。串行加载几条测线时界面干等着,体感很慢。

改成协程

换成 Kotlin 协程后,多测线并行加载就一段:

suspend fun loadMultiScanLines(files: List<RadarFile>): List<RadarData> = coroutineScope {
files.map { file ->
async(Dispatchers.IO) { readRadar(file) } // 每条测线一个异步任务
}.awaitAll() // 并行,全部完成后返回
}

对比 Thread 方案的收益:

  • 结构化并发:所有 async 任务挂在同一个 coroutineScope 下,scope 取消时子任务自动取消,不用手写标志位。
  • 线性可读async { ... }.awaitAll() 一眼看出是“并行多个、等全部”,比 Future.get 套回调清晰得多。
  • 异常传播:任一子任务抛异常会冒泡到 scope,配合 SupervisorJob 还能控制“一个失败不影响其他”。
  • 调度器切换Dispatchers.IO 读文件、Dispatchers.Main 刷 UI,用 withContext 切,线程边界明确。

配合生命周期

协程 scope 绑到 ViewModel 的生命周期,组件销毁时统一取消,不会出现“界面关了后台还在读文件、读完回调去刷新一个已销毁的 UI”这种空指针。

小结

协程相对 Thread 的核心优势是结构化并发 + 取消传播,并行加载这段代码从几十行缩到几行,可读性和正确性都好太多。后面导出、批量重算等并发场景也都统一到这套写法上。