개요
3장 CoroutineDispatcher에 대한 내용을 공부하고 정리한 글이다.
1. CoroutineDispatcher란?
먼저, Dispatcher라는 단어에 대해 분석해보면
'dispatch(보내다) + er' => '보내는 주체'
라는 뜻으로 해석된다.
즉, CoroutineDispatcher => '코루틴을 보내는 주체'
Coroutine을 보낸다? 어디로?
바로 스레드에다!
코루틴이란 것은 일시 중단 가능한 '작업'으로 스레드에서 실행할 수 있기 때문에 이 CoroutineDispatcher라는 객체는 코루틴을 스레드로 보내 실행시키는 역할을 한다.
1-1. CoroutineDispatcher의 동작
예시를 들어보자면,
코루틴을 실행시키는 2개의 스레드로 구성된 스레드풀을 사용할 수 있는 CoroutineDispatcher가 있다.
이미 Coroutine1이 Thread-1에서 실행 중이다.
이때, CoroutineDispatcher 객체에 Coroutine2 코루틴의 실행이 요청된다면 먼저, CoroutineDispatcher 객체는 실행 요청을 받은 코루틴을 작업 대기열에 넣는다.
그 뒤에 CoroutineDispatcher 객체가 사용할 수 있는 스레드가 어딘지 확인하고, 일을 하고 있지 않은 스레드에 작업 대기열에 적재된 Coroutine2를 보내서 실행시킨다.
But!, 코루틴이 모두 스레드를 점유하고 있어 사용할 수 있는 스레드가 없다면 어떻게 될까?
사용자로부터 Coroutine3을 실행시킬 것을 요청받았다.
이때, 사용할 수 없는 스레드가 없기 때문에 Coroutine3 코루틴을 스레드에 보내지 못하고, 작업 대기열에서 대기하도록 둔다.
그 뒤, Coroutine1이 실행 완료되고 Thread-1이 빈다면, Coroutine3이 Thread-1로 다시 보내져 실행된다.
1-2. 제한된 디스패처
제한된 디스패처란, 이름에서 알 수 있듯이 일정한 개수의 스레드만 사용하고, 스레드 풀 크기에 제한이 있는 디스패처이다.
이와 반대로 스레드가 제한되지 않는 무제한 디스패처도 있는데 이는 나중에 정리하겠다.
단일 스레드 디스패처(Single-Thread Dispatcher)
-> 사용할 수 있는 스레드가 하나인 CoroutineDispatcher이다. =( 스레드 풀에 스레드가 SingleThread 하나)
-> newSingleThreadContext 함수를 통해 만들 수 있다.
val dispatcher : CoroutineDispatcher = newSingleThreadContext(name = "singleThread")
멀티 스레드 디스패처(Multi-Thread Dispatcher)
-> 2개 이상의 스레드를 사용할 수 있도록 하는 CoroutineDispatcher
-> newFixedThreadPoolContext 함수를 통해 만들 수 있다.
val multiThreadDispatcher : CoroutineDispatcher = newFixedThreadPoolContext(
nThreads = 2,
name = "multiThread"
)
: nThreads
-> 스레드의 개수 설정
: name
-> 스레드의 이름
스레드의 개수가 2개 이상인데 각 스레드의 이름은 어떻게 정의되느냐??
각 스레드는 'multiThread-1', 'multiThread-2' 이런식으로 이름이 정의된다.
fun main() = runBlocking<Unit> {
val multiThreadDispatcher : CoroutineDispatcher = newFixedThreadPoolContext(
nThreads = 2,
name = "multiThread"
)
launch(multiThreadDispatcher) {
println("[${Thread.currentThread().name} 실행]")
}
launch(multiThreadDispatcher) {
println("[${Thread.currentThread().name} 실행]")
}
}
-> 이렇게 코드를 실행하면? 코루틴 실행 속도에 따라 다르지만 여러번 실행해보면 아래와 같이 나온다.
1-3. CoroutineDispatcher 사용
우리가 만든 제한된 디스패처 사용하는 것은 위에 코드에서 해봤는데,
그럼 코루틴 내부에 코루틴은 어떻게 실행될까?
부모코루틴 & 자식 코루틴
코루틴이 계층 구조로 이루어져 있을 수 있는데,
바깥쪽의 코루틴을 부모 코루틴(Parent Coroutine),
내부에서 생성된 코루틴을 자식 코루틴(Child Coroutine) 이라고 한다.
여기서 중요한 것은, 자식 코루틴에 CoroutineDispatcher 객체가 설정되어 있지 않다면, 부모 코루틴의 CoroutineDispatcher 객체를 그대로 사용한다.
fun main() = runBlocking<Unit> {
val multiThreadDispatcher : CoroutineDispatcher = newFixedThreadPoolContext(
nThreads = 2,
name = "multiThread"
)
launch(multiThreadDispatcher) {
println("[${Thread.currentThread().name} 부모 코루틴 실행]")
launch {
println("[${Thread.currentThread().name} 자식 코루틴 실행]")
}
launch {
println("[${Thread.currentThread().name} 자식 코루틴 실행]")
}
}
}
-> 부모 코루틴과, 자식 코루틴 모드 공통의 CoroutineDispatcher 객체를 사용하기 때문에 multiThread를 공용으로 사용하는 것이 나온다.
1-4. 정의된 CoroutineDispatcher
직접 CoroutineDispatcher 객체를 만들 수 있지만, 이것은 스레드를 생성하는 것이기 때문에 비용이 비싸다!
그래서 코루틴 라이브러리에서는 미리 정의된 CoroutineDispatcher의 목록들을 제공해준다.
Dispatchers.IO
-> 네트워크 요청 및 파일 입출력 등의 입출력(I/O) 작업을 위한 객체
Dispatchers.Default
-> CPU를 많이 사용하는 연산 작업을 위한 객체
Dispatchers.Main
-> 메인 스레드를 사용하기 위한 객체
이렇게 따로 라이브러리에서 제공해주기 때문에 우리는 위에 직접 만들었던 것 같이 따로 CoroutineDispatcher를 만들 필요가 없다!
각각의 Dispatcher 객체에 대한 특징을 정리해보겠다.
Dispatchers.IO
-> 최대로 사용할 수 있는 스레드의 수는 MAX(JVM에서 사용 가능한 프로세스의 수 , 64)가 된다.
-> 이 객체를 통해 여러 입출력 작업들을 동시에 수행할 수 있다.
fun main() = runBlocking<Unit> {
launch(Dispatchers.IO) {
println("[${Thread.currentThread().name} 코루틴 실행")
}
}
-> 엥 DefulatDispatcher-worker? 여기서 뭔가 이상함을 느꼈다. IO인데 왜 Default일까 뒤에 내용이 나온다.
-> 일단, DefulatDispatcher-worker 스레드는 코루틴 라이브러리에서 제공하는 공유 스레드풀에 속한 스레드이다.
Dispatchers.Default
-> CPU 연산이 직접 필요한 작업을 CPU 바운드 작업이라고 하는데, 이 작업이 필요할때 Dispatchers.Default 객체를 사용한다.
fun main() = runBlocking<Unit> {
launch(Dispatchers.Default) {
println("[${Thread.currentThread().name} 코루틴 실행")
}
}
-> 얘도, DefaultDispatcher-worker 스레드이다!
Dispatchers.IO와 Dispatchers.Default의 공유 스레드풀
-> 두 Dispatcher 객체 모두 코루틴 라이브러리의 공유 스레드풀을 사용하기 때문에 사용하는 스레드가 똑같이 나온다.
-> 코루틴 라이브러리에서는 스레드의 생성 및 관리를 효율적으로 할 수 있도록 애플리케이션 레벨의 공유 스레드풀을 제공한다.
-> 하지만 스레드 풀 내에서 Dispatchers.IO와 Dispatchers.Defulat가 사용하는 스레드가 구분된다고 한다.
Dispatchers.Main
-> 이 객체는 별도의 라이브러리(kotinx-coroutines-android 등)를 추가해야 사용할 수 있다고 한다.
'Android > Coroutine' 카테고리의 다른 글
[Coroutine] 코루틴 빌더와 Job (0) | 2025.03.12 |
---|---|
[Coroutine] 코루틴이란? (0) | 2025.03.04 |