코루틴의 개념과 사용 이유 - swkim0128/PARA GitHub Wiki
코루틴(Coroutine)은 코틀린에서 제공하는 경량 스레드로, 비동기 작업을 효율적으로 처리할 수 있는 기능입니다.
비동기 프로그래밍을 간결하게 구현하고, 스레드보다 더 가벼운 실행 단위를 제공합니다.
코루틴의 핵심 개념
- ✅ 비동기(Asynchronous) 프로그래밍을 쉽게 구현 가능.
- ✅ 경량 스레드 (Lightweight thread): 수천 개의 코루틴을 실행할 수 있음.
- ✅ 메모리 효율적: 스레드보다 가볍고, 필요할 때만 실행되며, 블로킹(blocking) 없이 동작.
- ✅ 구조적 동시성(Structured Concurrency) 제공.
- ✅ 스레드 대신 디스패처(Dispatcher)를 사용하여 실행 컨텍스트 관리.
- 코루틴은 기존 스레드보다 훨씬 적은 리소스를 사용합니다.
- 스레드 생성 비용이 없으며, 필요할 때만 실행됨.
- 콜백(callback) 지옥을 피할 수 있음.
- 비동기 코드를 순차적 코드처럼 작성할 수 있어 가독성이 향상됨.
- suspend 키워드를 사용하여 특정 지점에서 작업을 중단(suspend)하고 나중에 다시 재개(resume)할 수 있음.
- 코루틴 스코프(CoroutineScope)를 사용하여 작업을 관리하고, 자동으로 취소할 수 있음.
import kotlinx.coroutines.*
fun main() = runBlocking {
launch {
delay(1000L)
println("코루틴 실행!")
}
println("메인 함수 실행")
}✅ 출력 결과:
메인 함수 실행
(1초 후)
코루틴 실행!
설명:
- runBlocking → 메인 스레드를 블로킹하며 코루틴을 실행.
- launch → 새로운 코루틴을 시작.
- delay(1000L) → 1초 동안 코루틴을 일시 중단(suspend).
- suspend 키워드를 사용하면 코루틴 내에서 실행할 수 있는 비동기 함수를 만들 수 있음.
예제
import kotlinx.coroutines.*
suspend fun doWork() {
delay(2000L) // 2초 동안 중단
println("작업 완료!")
}
fun main() = runBlocking {
doWork() // suspend 함수 호출
println("메인 함수 종료")
}✅ 출력 결과:
(2초 후)
작업 완료!
메인 함수 종료
설명:
- suspend fun → 일시 중단 가능한 함수.
- delay(2000L) → 2초 동안 중단되었다가 재개.
- launch {} → 작업을 실행하고 결과를 반환하지 않음 (Job 반환).
- async {} → 결과를 반환하는 작업을 실행 (Deferred<T> 반환, .await() 필요).
fun main() = runBlocking {
val job = launch {
delay(1000L)
println("launch 실행 완료!")
}
println("메인 실행 중...")
job.join() // job이 끝날 때까지 기다림
}✅ 출력 결과:
메인 실행 중...
(1초 후)
launch 실행 완료!
fun main() = runBlocking {
val deferred = async {
delay(1000L)
"async 실행 완료!"
}
println("메인 실행 중...")
println(deferred.await()) // 결과를 기다린 후 출력
}✅ 출력 결과:
메인 실행 중...
(1초 후)
async 실행 완료!
설명:
- async는 값을 반환할 수 있으며, .await()를 사용해 값을 가져옴.
- 코루틴을 적절한 컨텍스트에서 실행하고 관리하기 위해 CoroutineScope를 사용함.
import kotlinx.coroutines.*
fun main() {
GlobalScope.launch {
delay(1000L)
println("GlobalScope 실행!")
}
println("메인 함수 종료") // 실행될 수도 있고 안 될 수도 있음 (메인 종료 시 코루틴 종료)
Thread.sleep(2000L) // 프로그램이 종료되지 않도록 유지
}✅ 주의: GlobalScope는 전역적으로 실행되므로 관리가 어려움. 가능하면 CoroutineScope를 사용하는 것이 좋음.
fun main() = runBlocking {
println("runBlocking 시작")
coroutineScope {
launch {
delay(1000L)
println("coroutineScope 내부 실행")
}
}
println("runBlocking 종료")
}✅ runBlocking은 전체 프로그램을 블로킹하지만, coroutineScope는 블로킹하지 않음.
코루틴을 실행할 스레드를 결정할 때 사용됨.
| 디스패처 | 설명 |
|---|---|
| Dispatchers.Default | CPU 작업(연산 집중) |
| Dispatchers.IO | I/O 작업(파일, 네트워크) |
| Dispatchers.Main | UI 작업(Android) |
| Dispatchers.Unconfined | 현재 스레드에서 실행 |
예제
fun main() = runBlocking {
launch(Dispatchers.Default) { println("Default 실행") }
launch(Dispatchers.IO) { println("IO 실행") }
}코루틴을 취소하려면 job.cancel()을 사용합니다.
예제
fun main() = runBlocking {
val job = launch {
repeat(1000) { i ->
println("작업 실행 중... $i")
delay(500L)
}
}
delay(2000L)
job.cancel() // 코루틴 취소
println("작업 취소됨")
}✅ 취소 가능 작업(delay)이 없으면 취소되지 않으므로 isActive를 사용해야 함.
✅ 코루틴은 비동기 작업을 쉽게 구현하고 스레드보다 가볍게 동작함. ✅ 스레드 블로킹 없이도 중단(suspend)과 재개(resume)이 가능함. ✅ launch는 값을 반환하지 않고, async는 값을 반환하며 await()로 결과를 가져옴. ✅ Dispatchers를 사용하여 적절한 실행 환경에서 실행 가능. ✅ 구조적 동시성을 지원하여 코루틴의 생명주기를 안전하게 관리할 수 있음.
💡 코루틴을 활용하면 효율적이고 가독성 높은 비동기 프로그래밍을 할 수 있습니다! 🚀