안드로이드 개발을 하다 보면 여러 개의 비동기 작업(API 호출 등)을 동시에 병렬로 실행하고, 그 결과를 Flow로 처리하고 싶은 경우가 자주 발생합니다. Kotlin의 Flow는 기본적으로 순차적 처리에 최적화되어 있지만, 병렬 처리를 위해 몇 가지 강력한 방법들을 제공합니다.
이 글에서는 Kotlin Flow에서 비동기 API를 병렬로 호출하는 주요 방법을 세 가지로 정리해보겠습니다.
flow에서 비동기 처리를 병렬로 하는 방법
ID 목록을 받아 각 ID에 대해 비동기 API 호출을 병렬로 처리하고 결과를 수집하는 상황을 가정해봅니다.
fun idsFlow(): Flow<Int> = flowOf(1, 2, 3, 4, 5)
suspend fun fetchData(id: Int): String {
delay(1000) // 비동기 API 호출을 시뮬레이션
return "Data for $id"
}
1. flatMapMerge 사용 (권장)
fun main() = runBlocking {
idsFlow()
.flatMapMerge(concurrency = 3) { id ->
flow { emit(fetchData(id)) }
}
.collect { result ->
println("✅ 결과: $result")
}
}
설명
- flatMapMerge는 여러 Flow를 병렬로 실행해주는 연산자입니다.
- flatMapConcat은 순차, flatMapMerge는 동시, flatMapLatest는 가장 최신 값만 유지
- concurrency 파라미터를 통해 동시 실행 수 제한 가능
- concurrency = N → 최대 N개의 코루틴을 동시에 실행할지 (코루틴 동시 실행 수 제한)
- 하지만 이 코루틴들이 몇 개의 스레드를 사용할지는 디스패처(Dispatcher) 설정에 따름
- 예: Dispatchers.Default라면 공통 스레드 풀 위에서 돌아가고,
- Dispatchers.IO면 IO 스레드 풀 위에서 돌아갑니다.
- Flow 내에서 자연스럽게 병렬 비동기 처리 구현 가능
2. map + async + awaitAll 조합
fun main() = runBlocking {
val results = coroutineScope {
idsFlow()
.map { id -> async { fetchData(id) } }
.toList() // Deferred 리스트로 변환
.awaitAll() // 병렬 결과 수집
}
results.forEach { println("✅ 결과: $it") }
}
설명
- map { async { ... } }로 병렬로 작업 실행
- awaitAll()을 통해 전체 결과를 모아서 한 번에 처리
- 단점: 이 방식은 Flow가 아니라 List로 결과를 받게 됨 (일괄 처리 시 적합)
- Flow로 직접 collect하지 않기 때문에 일괄 처리에 적합
- Flow로 직접 collect하지 않기 때문에 일괄 처리에 적합
3. channelFlow + launch 조합
fun fetchMultipleData(ids: List<Int>): Flow<String> = channelFlow {
ids.forEach { id ->
launch {
val data = fetchData(id)
send(data)
}
}
}
fun main() = runBlocking {
fetchMultipleData(listOf(1, 2, 3, 4, 5))
.collect { println("✅ 결과: $it") }
}
설명
- channelFlow는 내부에서 send()를 사용해 비동기 데이터를 보낼 수 있습니다.
- launch를 통해 각 비동기 작업을 병렬 실행
- 복잡한 병렬 흐름을 제어할 때 유용
정리
방법 | 병렬성 | 특징 |
flatMapMerge | ✅ | 가장 직관적이고 Flow 친화적 병렬 처리 방식 |
map + async + awaitAll | ✅ | 비동기 결과를 한꺼번에 수집할 때 적합 |
channelFlow | ✅ | 복잡한 병렬 흐름이나 커스텀 처리에 유리 |
끝.
'Android > Flow' 카테고리의 다른 글
[Android] Flow 결합 연산자: zip과 combine 차이 (0) | 2025.04.29 |
---|---|
[Android] Flow의 emit은 왜 suspend함수일까? (0) | 2025.04.13 |
[Android] StateFlow의 원자성 보장 방법 (feat. update) (0) | 2025.02.18 |
[Android] 이벤트 처리 Channel vs SharedFlow (0) | 2025.02.18 |
[Android] 안드로이드 환경의 Flow Lifecycle (0) | 2025.02.17 |