在使用Kotlin协程时,经常使用到launch和async,都新协程的构建器,这里简单记录一下,方便自己查阅和学习。
正文
launch
launch即发即忘的后台任务。
当你只关心任务是否执行,而不关心其返回结果时,应使用 launch。它返回的 Job 对象仅用于管理协程的生命周期,例如取消任务或等待其完成。
典型场景:埋点上报、日志记录、UI 状态刷新、发送通知等。
fun main() = runBlocking {
val job = launch {
delay(1000L) // 模拟耗时操作
//略
}
// 如果需要,可以等待任务完成
job.join()
}async
async并发执行并汇总结果。
当你需要同时执行多个耗时任务,并等待所有结果返回后再进行下一步处理时,async 是最佳选择。它返回的 Deferred<T> 对象封装了异步计算的结果,必须通过 await() 来获取。
典型场景:并行请求多个网络接口、并发处理数据、存在数据依赖的并发任务等。
fun main() = runBlocking {
val userDeferred = async {
delay(1000L) // 模拟网络请求
//用户数据处理
}
val orderDeferred = async {
delay(1000L) // 模拟网络请求
//订单数据处理
}
// 等待两个任务都完成并获取结果
val user = userDeferred.await()
val order = orderDeferred.await()
}小结
async必须调用 await()如果启动了
async却忘记调用await(),不仅无法获取结果,其内部抛出的异常也会被静默吞掉,导致难以排查的 Bug。避免过度设计如果任务之间是顺序依赖关系,或者没有并发需求,直接在
launch中按顺序调用挂起函数即可,代码更直观。对于单个需要返回结果的耗时任务,使用withContext比async { ... }.await()语义更清晰、开销更小。异常处理机制不同
launch中的异常会立即抛出,而async中的异常只有在调用await()时才会抛出。在使用async时,务必将await()放在try-catch块中,以确保异常能被正确捕获和处理。
对比
| 特性 | launch | async |
|---|---|---|
| 设计语义 | 启动一个任务(即发即忘) | 启动一个带结果的任务 |
| 返回类型 | Job | Deferred<T> |
| 获取结果 | 不支持 | 必须通过 await() 获取 |
| 异常处理 | 异常立即传播,可能导致协程取消或崩溃 | 异常被暂存,直到调用 await() 时才抛出 |

