Kotlin协程:并行执行IO任务并统一捕获异常
解决Kotlin协程并行任务统一捕获异常的问题
要实现两个并行IO任务(持续ping服务器+单次网络请求)且任一异常被同一catch块捕获,核心是利用coroutineScope管理子协程——它能自动传递子协程的异常到外层,同时保证任务并行执行。
为什么之前的写法失效?
- 顺序执行的问题:如果直接在try块内先调用
pingServer()再调用makeNetworkCall(),由于pingServer()是持续挂起的无限循环,代码永远不会走到makeNetworkCall()。 - launch的异常逃逸问题:用外部作用域的
launch启动pingServer()时,子协程的异常会直接抛到作用域的异常处理器,无法被当前try-catch捕获——因为launch是"fire-and-forget"模式,其异常不会向上传递到当前函数的try块。
正确实现方案
使用coroutineScope创建子协程作用域:
coroutineScope会等待所有内部子协程完成,且任何子协程抛出异常时,会取消其他子协程并将异常向上传递。- 在
coroutineScope内用launch启动持续运行的ping任务,同时直接执行单次网络请求(或用launch/async)。 - 外层用try-catch包裹
coroutineScope的调用,即可统一捕获两个任务的异常。
完整代码示例
import kotlinx.coroutines.* import java.io.IOException // 模拟持续ping服务器的suspend函数 suspend fun pingServer() { while (true) { delay(10000) // 模拟随机ping失败 if ((0..10).random() == 5) { throw IOException("Ping服务器超时") } println("[Ping] 服务器可达") } } // 模拟OkHttp网络请求的suspend函数 suspend fun makeNetworkCall(): String { delay(5000) // 模拟网络耗时 // 模拟随机请求失败 if ((0..10).random() == 3) { throw IOException("请求接口返回500") } return "[网络请求] 成功获取数据:{...}" } // 封装的并行执行逻辑 suspend fun runParallelTasks() = coroutineScope { // 启动ping子协程 val pingJob = launch { pingServer() } try { // 执行网络请求(与ping并行) val response = makeNetworkCall() println(response) } finally { // 网络请求完成/异常后,停止ping任务 pingJob.cancelAndJoin() println("[Ping] 任务已终止") } } // 调用入口 fun main() = runBlocking { try { runParallelTasks() } catch (e: Exception) { // 统一处理所有异常 println("[异常捕获] ${e.message}") } }
关键细节说明
coroutineScope是suspend函数,它会绑定当前协程的上下文,内部子协程的异常会被它捕获并向上抛出,因此外层的try-catch能捕获到所有异常。pingJob.cancelAndJoin()确保网络请求完成或异常发生后,ping任务被正确终止,避免不必要的资源占用。- 如果ping任务不需要随网络请求结束而停止,可去掉finally块的取消逻辑,但此时
coroutineScope会一直挂起,直到ping任务抛出异常。
内容的提问来源于stack exchange,提问作者SVK
相关产品推荐
相关产品推荐

