티스토리 뷰
728x90
2. 코루틴 스코프 및 컨텍스트
2.1 코루틴 스코프(Coroutine Scope)란?
코루틴 스코프는 코루틴의 수명을 관리하는 역할을 합니다. 코루틴은 스코프 내에서만 실행되며, 스코프가 종료되면 그 스코프 내에서 실행된 모든 코루틴도 자동으로 취소됩니다. 이는 구조화된 동시성을 구현하는 중요한 개념으로, 비동기 작업이 여러 개 실행되더라도 일정한 흐름 안에서 안전하게 관리될 수 있도록 해줍니다.
코루틴은 여러 개의 스코프에서 동작할 수 있으며, 대표적으로 두 가지 스코프를 사용할 수 있습니다:
- GlobalScope: 앱이 종료되기 전까지 코루틴이 계속 실행됩니다. 하지만 자원을 낭비할 수 있기 때문에 권장되지 않습니다.
- CoroutineScope: 특정한 범위에서만 코루틴이 실행되며, 해당 범위가 끝나면 코루틴이 취소됩니다. 보통
launch
나async
에서 사용됩니다.
2.2 GlobalScope vs CoroutineScope
- GlobalScope는 앱이 종료될 때까지 모든 코루틴을 지속적으로 실행할 수 있지만, 구조화된 동시성(structured concurrency)을 보장하지 않기 때문에 앱이나 프로젝트의 크기가 커질수록 비효율적이고 예외 처리도 복잡해집니다.
- CoroutineScope는 스코프의 수명을 관리하면서 코루틴이 안전하게 종료되도록 합니다. 대부분의 경우에
CoroutineScope
을 사용하는 것이 바람직하며, 특정 수명 동안만 코루틴을 실행하려면 이를 사용해야 합니다.
다음은 GlobalScope
와 CoroutineScope
의 차이를 보여주는 간단한 예제입니다.
2.3 코루틴 스코프 사용 예제
import kotlinx.coroutines.*
fun main() {
// GlobalScope 사용 예제
GlobalScope.launch {
delay(1000L)
println("GlobalScope: I'm still running!")
}
// runBlocking 스코프 사용 예제
runBlocking {
launch {
delay(500L)
println("CoroutineScope: I'm running within the scope!")
}
println("runBlocking: Waiting for the coroutine inside to finish.")
}
println("Main program continues...")
Thread.sleep(2000L) // GlobalScope 코루틴이 실행될 시간을 주기 위해 추가한 코드
}
코드 설명
- GlobalScope.launch:
- 이 코루틴은 앱의 생명주기 전체 동안 실행됩니다.
GlobalScope.launch
는 1초 후에"GlobalScope: I'm still running!"
을 출력하지만, 해당 코루틴은 별도의 스레드에서 실행되므로runBlocking
이 끝난 후에도 여전히 실행됩니다.
- 이 코루틴은 앱의 생명주기 전체 동안 실행됩니다.
- runBlocking 스코프:
runBlocking
은 현재 스레드를 블로킹하며, 그 안에서 실행된 모든 코루틴이 끝날 때까지 기다립니다. 이 스코프 내에서 코루틴이 실행되면, 스코프가 끝나는 시점에 모든 코루틴도 종료됩니다.
- Thread.sleep(2000L):
- 이 코드는
GlobalScope
에서 실행된 코루틴이 완료될 수 있도록 시간을 주는 용도로 삽입되었습니다. 그렇지 않으면 메인 프로그램이 먼저 종료될 수 있습니다.
- 이 코드는
출력 결과:
runBlocking: Waiting for the coroutine inside to finish.
CoroutineScope: I'm running within the scope!
Main program continues...
GlobalScope: I'm still running!
runBlocking
내의 코루틴은 500ms 후에"CoroutineScope: I'm running within the scope!"
를 출력한 뒤 종료됩니다.- 반면
GlobalScope.launch
는 1초 후에"GlobalScope: I'm still running!"
을 출력합니다. 이때 메인 스레드는 이미println("Main program continues...")
를 출력하고 기다리는 상태입니다.
2.4 코루틴 컨텍스트 및 디스패처
코루틴은 **컨텍스트(Context)**에서 실행됩니다. 컨텍스트는 코루틴이 어떤 스레드에서 실행될지와 같은 실행 환경을 정의합니다. 이때 주로 사용되는 디스패처(Dispatcher)는 다음과 같습니다:
- Dispatchers.Default:
- CPU 집약적인 작업을 위해 사용됩니다.
- 기본적으로 코틀린이 관리하는 스레드 풀에서 실행됩니다.
- 백그라운드에서 실행되는 CPU 중심의 작업에 적합합니다.
- Dispatchers.IO:
- 파일 입출력, 네트워크 요청과 같은 입출력 작업에 최적화된 디스패처입니다.
- 입출력 작업은 CPU 작업보다는 느리지만 자주 대기 상태에 있으므로, 스레드를 효율적으로 활용합니다.
- Dispatchers.Main:
- 안드로이드나 UI 기반 애플리케이션에서 UI 스레드에서 코루틴을 실행하기 위한 디스패처입니다.
- UI 작업을 처리할 때 사용되며, 안드로이드 환경에서 자주 사용됩니다.
간단한 예제
다양한 디스패처를 사용하여 코루틴이 어떻게 실행되는지 확인해보겠습니다.
import kotlinx.coroutines.*
fun main() = runBlocking {
// Default Dispatcher
launch(Dispatchers.Default) {
println("Running on Dispatchers.Default: ${Thread.currentThread().name}")
delay(1000L)
}
// IO Dispatcher
launch(Dispatchers.IO) {
println("Running on Dispatchers.IO: ${Thread.currentThread().name}")
delay(1000L)
}
// Main Dispatcher (안드로이드 UI 스레드에서 사용)
// launch(Dispatchers.Main) {
// println("Running on Dispatchers.Main: ${Thread.currentThread().name}")
// delay(1000L)
// }
println("Main program continues on: ${Thread.currentThread().name}")
}
설명
- Dispatchers.Default:
- CPU 집약적인 작업을 처리하기 위한 디스패처로, 스레드 풀에서 실행됩니다.
"Running on Dispatchers.Default: DefaultDispatcher-worker-1"
같은 출력이 나옵니다.
- Dispatchers.IO:
- 입출력 작업에 적합한 디스패처로, 입출력 대기 시간이 많은 작업에서 효율적으로 처리됩니다.
"Running on Dispatchers.IO: DefaultDispatcher-worker-2"
같은 출력이 나옵니다.
- Dispatchers.Main:
- 이 디스패처는 안드로이드 앱의 UI 스레드에서 실행되도록 설계되었습니다. 데스크탑 환경에서는 사용되지 않으므로, 주석 처리했습니다.
출력 결과
Main program continues on: main
Running on Dispatchers.Default: DefaultDispatcher-worker-1
Running on Dispatchers.IO: DefaultDispatcher-worker-2
728x90
댓글