코틀린의 비동기 처리 (async, await)
코틀린에서는 비동기(Asynchronous) 처리를 위해 Coroutine(코루틴)을 활용함.
특히, async와 await 을 사용하면 비동기 작업을 실행하고 그 결과를 기다리는 방식으로 코드를 효율적으로 작성할 수 있음.
1️⃣ 비동기 처리의 필요성
코틀린에서 비동기 처리를 사용하는 이유:
• CPU 작업과 I/O 작업을 효율적으로 처리하기 위해
• 동기 코드보다 빠른 실행 가능 (여러 작업을 동시에 수행)
• 메인 스레드를 블로킹(blocking)하지 않음 (예: UI 애플리케이션에서 중요)
2️⃣ async 와 await 개념
• async {} → 비동기적으로 실행되는 작업을 정의
• await() → 비동기 작업의 결과를 반환받음 (suspend 함수에서만 사용 가능)
async 는 비동기적으로 실행되는 Deferred<T> (미래의 값을 담는 객체) 를 반환함.
즉, async를 사용하면 결과를 즉시 기다리지 않고 다른 작업을 수행할 수 있음.
3️⃣ async & await 기본 사용법
import kotlinx.coroutines.*
fun main() = runBlocking {
val deferred: Deferred<String> = async {
delay(2000) // 2초 대기 (비동기 처리)
"Hello, Kotlin!"
}
println("비동기 작업 실행 중...")
val result = deferred.await() // 결과를 기다림
println("결과: $result")
}
출력 결과
비동기 작업 실행 중...
(2초 후)
결과: Hello, Kotlin!
✅ 비동기 실행:
• async 내부에서 delay(2000) 동안 대기하면서, 메인 스레드는 블로킹되지 않음.
• await()을 호출하면 결과를 기다린 후 반환함.
4️⃣ async를 활용한 병렬 실행
async를 여러 개 사용하면 여러 작업을 병렬로 실행할 수 있음.
import kotlinx.coroutines.*
fun main() = runBlocking {
val time = measureTimeMillis {
val task1 = async { fetchData1() }
val task2 = async { fetchData2() }
println("결과: ${task1.await()} + ${task2.await()}")
}
println("총 실행 시간: $time ms")
}
suspend fun fetchData1(): String {
delay(2000) // 네트워크 요청 시뮬레이션
return "데이터1"
}
suspend fun fetchData2(): String {
delay(3000) // 다른 요청
return "데이터2"
}
출력 결과
결과: 데이터1 + 데이터2
총 실행 시간: 3000 ms
✅ 병렬 실행 효과:
• fetchData1()과 fetchData2()는 async 덕분에 동시에 실행됨.
• 전체 실행 시간이 2초 + 3초 = 5초가 아니라 3초만 소요됨 (병렬 처리 덕분).
5️⃣ async와 launch의 차이점
비교 항목 | async | launch |
반환값 | Deferred<T> (결과를 반환) | Job (결과 없음) |
사용 목적 | 비동기 연산 후 결과 반환 | 단순한 비동기 실행 |
await() 사용 가능 여부 | ✅ 가능 (await()로 결과 반환) | ❌ 사용 불가 |
예제 | async { fetchData() } | launch { doSomething() } |
예제 비교
import kotlinx.coroutines.*
fun main() = runBlocking {
val job = launch {
println("launch 실행")
}
val deferred = async {
"async 결과 반환"
}
println("async 결과: ${deferred.await()}") // ✅ 가능
// println("launch 결과: ${job.await()}") // ❌ 에러 발생 (launch는 await 불가)
}
✅ 정리:
• launch → 단순 실행용 (결과가 필요 없을 때)
• async → 비동기적으로 실행하고 결과를 받아야 할 때
6️⃣ async에서 예외 처리 (try-catch)
비동기 코드에서 예외가 발생하면 처리해줘야 함.
예외가 발생하면 await()를 호출하는 시점에서 예외가 던져짐.
import kotlinx.coroutines.*
fun main() = runBlocking {
val deferred = async {
try {
delay(1000)
throw Exception("에러 발생!")
} catch (e: Exception) {
println("비동기 예외 처리: ${e.message}")
"기본값 반환"
}
}
println("결과: ${deferred.await()}")
}
출력 결과
비동기 예외 처리: 에러 발생!
결과: 기본값 반환
✅ 예외 처리 가능!
• try-catch를 async 내부에서 사용하여 예외가 발생해도 안전하게 처리할 수 있음.
7️⃣ supervisorScope를 활용한 예외 처리
• 기본적으로 async는 한 개의 예외가 발생하면 전체 코루틴이 중단됨.
• supervisorScope를 사용하면 하나의 코루틴이 실패해도 다른 코루틴이 계속 실행됨.
import kotlinx.coroutines.*
fun main() = runBlocking {
supervisorScope {
val task1 = async {
delay(1000)
throw Exception("task1 실패!")
}
val task2 = async {
delay(2000)
"task2 성공!"
}
try {
println("결과: ${task1.await()} + ${task2.await()}")
} catch (e: Exception) {
println("예외 발생: ${e.message}")
}
}
}
출력 결과
예외 발생: task1 실패!
✅ task1은 실패했지만, task2는 계속 실행됨.
8️⃣ 정리
• async → 비동기 작업 실행 (결과 반환 가능)
• await() → 비동기 작업의 결과를 기다림
• 여러 개의 async를 사용하면 병렬 처리 가능
• 예외 처리는 try-catch 또는 supervisorScope를 활용
• 비동기 실행만 하고 결과가 필요 없으면 launch 사용
출처 : ChatGPT
'BE > Kotlin' 카테고리의 다른 글
[Kotlin] as? 와 null 형변환 (0) | 2025.03.27 |
---|---|
[Kotlin] 코루틴 (Coroutines) (1) | 2025.03.02 |
[Kotlin] 함수형 프로그래밍과 불변성 (0) | 2025.02.24 |
[Kotlin] JPA에서 필드에 final을 붙이지 않는 이유 (val, var) (0) | 2025.02.21 |
[Kotlin] 코틀린 문법 6 (open, 상속, 인터페이스) (0) | 2025.02.20 |