题目
实现并发网络请求并处理结果聚合
信息
- 类型:问答
- 难度:⭐⭐
考点
结构化并发, async/await模式, 异常处理, 协程作用域管理
快速回答
实现要点:
- 使用
coroutineScope创建结构化并发作用域 - 通过
async启动并发任务 - 使用
awaitAll()等待所有结果 - 异常处理需结合
try-catch和CoroutineExceptionHandler - 避免使用
GlobalScope防止内存泄漏
场景需求
需要并发请求三个API接口(用户数据/订单数据/商品数据),聚合结果后统一处理,任一请求失败需取消其他请求并返回错误信息。
核心实现代码
suspend fun fetchCombinedData(): Result<CombinedData> = coroutineScope {
val userDeferred = async { fetchUserData() }
val orderDeferred = async { fetchOrderData() }
val productDeferred = async { fetchProductData() }
try {
val results = awaitAll(userDeferred, orderDeferred, productDeferred)
Result.success(combineResults(results))
} catch (e: Exception) {
Result.failure(e)
}
}
// 实际网络请求函数(模拟)
suspend fun fetchUserData(): UserData {
delay(1000)
return UserData() // 实际应使用Retrofit等网络库
}原理说明
- 结构化并发:
coroutineScope创建的子作用域会等待所有子协程完成,任一子协程失败将自动取消其他子协程 - async/await模式:
async启动并发任务返回Deferred对象,await()获取结果 - 异常传播:子协程异常会传播到父协程,触发作用域内取消
最佳实践
- 作用域管理:使用
viewModelScope或lifecycleScope避免内存泄漏 - 错误处理:
val handler = CoroutineExceptionHandler { _, e -> // 统一处理未捕获异常 } viewModelScope.launch(handler) { ... } - 超时控制:使用
withTimeout(3000)设置全局超时
常见错误
- 错误1:忘记调用
await()导致并发失效 - 错误2:使用
GlobalScope引发内存泄漏 - 错误3:在
async块外捕获异常导致崩溃 - 错误4:未处理
CancellationException干扰协程取消
扩展知识
- 结果聚合优化:使用
listOf(deferred1, deferred2).awaitAll() - 部分成功处理:
val results = listOf(userDeferred, orderDeferred) .map { deferred -> runCatching { deferred.await() } } - 性能考量:超过5个并发请求建议使用
Dispatchers.IO.limitedParallelism(5)限制线程数