⚡ 1. 코루틴(Coroutines)란?
코루틴(Coroutine) 은 Kotlin에서 제공하는 비동기 프로그래밍을 위한 경량 쓰레드 개념입니다.
기존의 Thread나 RxJava보다 가볍고 효율적으로 비동기 작업을 관리할 수 있도록 설계되었습니다.
✅ 코루틴의 주요 특징
🔹 경량성 → 수천 개의 코루틴을 실행해도 적은 리소스를 사용
🔹 비동기 & 논블로킹 → 메인 쓰레드를 차단하지 않고 동작
🔹 구조적 동시성(Structured Concurrency) → CoroutineScope를 활용해 일괄적으로 관리 가능
🔹 기존 코드와의 쉬운 통합 → 기존 Thread, RxJava보다 간결한 코드 작성 가능
⚡ 2. 코루틴의 기본 개념
🏗 코루틴의 주요 구성 요소
개념 | 설명 |
CoroutineScope | 코루틴이 실행되는 범위를 정의 (예: GlobalScope, MainScope, viewModelScope) |
launch | 새로운 코루틴을 실행 (결과값 없음, Job 반환) |
async | 값을 반환하는 코루틴 실행 (Deferred<T> 반환, await()로 값 얻기) |
suspend | 일시 중단이 가능한 함수 (delay(), withContext(), await() 같은 함수에서 사용) |
withContext | 특정 쓰레드 컨텍스트에서 코드 실행 (Dispatchers.IO, Dispatchers.Main 등) |
Job | 코루틴의 실행 단위를 나타내며, cancel()을 호출하여 중단 가능 |
Deferred | async가 반환하는 결과값을 나타내며, await()으로 값을 가져올 수 있음 |
⚡ 3. 코루틴 기본 예제
✅ 1) launch로 코루틴 실행
import kotlinx.coroutines.*
fun main() = runBlocking {
launch {
delay(1000L)
println("코루틴 실행 완료!")
}
println("메인 실행")
}
🖥️ 출력 결과
메인 실행
(1초 후)
코루틴 실행 완료!
🔹 launch는 비동기로 실행되며, delay(1000L) 동안 대기 후 "코루틴 실행 완료!"를 출력
✅ 2) async로 결과값 반환
import kotlinx.coroutines.*
fun main() = runBlocking {
val result = async {
delay(1000L)
"Hello, Coroutines!"
}
println("메인 실행")
println(result.await()) // await()을 호출해야 결과를 받을 수 있음
}
🖥️ 출력 결과
메인 실행
(1초 후)
Hello, Coroutines!
🔹 async는 값을 반환하는 코루틴을 실행하며, await()을 호출해야 결과를 받을 수 있음.
⚡ 4. 코루틴의 실행 컨텍스트 (Dispatchers)
Kotlin 코루틴에서는 작업을 실행할 쓰레드를 지정하는 Dispatchers 를 사용할 수 있습니다.
Dispatcher | 설명 |
Dispatchers.Main | UI 작업 수행 (Android에서 주로 사용) |
Dispatchers.IO | I/O 작업 수행 (파일 읽기, 네트워크 요청 등) |
Dispatchers.Default | CPU 연산이 집중된 작업 수행 (데이터 처리, 대규모 계산) |
Dispatchers.Unconfined | 처음 호출된 쓰레드에서 실행되지만, 이후 상황에 따라 변경 가능 |
newSingleThreadContext("Thread") | 새로운 단일 쓰레드를 생성하여 실행 |
✅ 1) Dispatchers.IO에서 네트워크 작업 수행
import kotlinx.coroutines.*
fun main() = runBlocking {
launch(Dispatchers.IO) { // IO 작업을 위한 컨텍스트 지정
val result = fetchData()
println(result)
}
}
suspend fun fetchData(): String {
delay(1000L)
return "데이터 가져오기 완료!"
}
🔹 Dispatchers.IO는 네트워크 요청 또는 파일 I/O 작업을 수행할 때 적합.
🔹 fetchData()는 suspend 함수이므로 코루틴 안에서만 호출 가능.
✅ 2) withContext()로 컨텍스트 변경
import kotlinx.coroutines.*
fun main() = runBlocking {
val result = withContext(Dispatchers.IO) { fetchData() }
println(result)
}
🔹 withContext(Dispatchers.IO)를 사용하면 특정 코드 블록만 IO 컨텍스트에서 실행 가능.
🔹 async(Dispatchers.IO)와 달리 withContext는 반환 값을 직접 받을 수 있음.
⚡ 5. 코루틴 예외 처리 (try-catch & CoroutineExceptionHandler)
✅ 1) try-catch로 예외 처리
import kotlinx.coroutines.*
fun main() = runBlocking {
launch {
try {
riskyTask()
} catch (e: Exception) {
println("에러 발생: ${e.message}")
}
}
}
suspend fun riskyTask() {
delay(1000L)
throw IllegalStateException("예상치 못한 오류 발생!")
}
🖥️ 출력 결과
에러 발생: 예상치 못한 오류 발생!
🔹 try-catch를 사용하여 코루틴 내부에서 발생한 예외를 처리 가능.
✅ 2) CoroutineExceptionHandler로 예외 처리
import kotlinx.coroutines.*
fun main() = runBlocking {
val handler = CoroutineExceptionHandler { _, exception ->
println("예외 발생: ${exception.message}")
}
val job = GlobalScope.launch(handler) {
throw IllegalArgumentException("잘못된 입력값!")
}
job.join()
}
🖥️ 출력 결과
예외 발생: 잘못된 입력값!
🔹 CoroutineExceptionHandler는 launch에서 발생한 예외를 글로벌하게 처리 가능.
⚡ 6. 코루틴의 구조적 동시성 (SupervisorJob & scope 활용)
✅ 1) SupervisorJob을 활용한 독립적인 오류 처리
import kotlinx.coroutines.*
fun main() = runBlocking {
val supervisor = SupervisorJob()
val scope = CoroutineScope(Dispatchers.Default + supervisor)
scope.launch {
throw IllegalStateException("작업 실패!")
}
scope.launch {
delay(1000L)
println("다른 작업 정상 실행")
}
delay(2000L)
}
🖥️ 출력 결과
다른 작업 정상 실행
🔹 SupervisorJob을 사용하면 하나의 코루틴이 실패해도 다른 코루틴은 영향을 받지 않음.
⚡ 7. Flow를 활용한 비동기 데이터 스트림
✅ 1) Flow 기본 예제
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
flowExample().collect { value ->
println("받은 값: $value")
}
}
fun flowExample(): Flow<Int> = flow {
for (i in 1..5) {
delay(500L)
emit(i) // 값 방출
}
}
🖥️ 출력 결과
받은 값: 1
받은 값: 2
받은 값: 3
받은 값: 4
받은 값: 5
🔹 Flow는 비동기 데이터 스트림을 처리하는 방법으로, emit()을 사용해 값을 순차적으로 방출 가능.
🔹 collect()를 사용하여 Flow 데이터를 수집함.
⚡ 결론
• 코루틴은 가벼운 비동기 작업을 효율적으로 관리할 수 있도록 도와줌.
• launch는 단순 실행, async는 결과 반환 (await() 필요).
• Dispatchers를 활용해 원하는 쓰레드에서 실행 가능 (Main, IO, Default).
• 예외 처리는 try-catch 또는 CoroutineExceptionHandler로 가능.
• Flow를 사용하면 비동기 데이터 스트림을 쉽게 처리 가능.
🚀 코루틴을 활용하면 Kotlin에서 효율적이고 안전한 비동기 처리를 구현할 수 있음!
출처 : ChatGPT
'BE > Kotlin' 카테고리의 다른 글
[Kotlin] 비동기 처리 (async, await) (0) | 2025.03.29 |
---|---|
[Kotlin] as? 와 null 형변환 (0) | 2025.03.27 |
[Kotlin] 함수형 프로그래밍과 불변성 (0) | 2025.02.24 |
[Kotlin] JPA에서 필드에 final을 붙이지 않는 이유 (val, var) (0) | 2025.02.21 |
[Kotlin] 코틀린 문법 6 (open, 상속, 인터페이스) (0) | 2025.02.20 |