Coroutine을 공부하면서 CoroutineDispatcher에 대해 상세히 설명된 글이 없어서 이 글을 작성하게 되었다. 많은 사람들에게 도움이 되길 바란다.
CoroutineDispatcher 란 무엇인가?
코루틴을 시작하게 되면, CoroutineDispatcher란 단어를 가장 먼저 접하게 된다.
CoroutineDispatcher은 Coroutine과 Dispatcher 단어의 합성어이다. 여기서 Coroutine은 코루틴이며, Dispatch란 한국어로 '보내다' 라는 뜻이다. 즉, CoroutineDispatcher은 코루틴을 보내는 객체를 뜻한다. 그렇다면 CoroutineDispatcher은 코루틴을 어디로 보낼까? 바로 스레드(Thread)로 보낸다.
모든 작업은 스레드 위에서 실행돼야 하고, 코루틴 또한 작업이므로 스레드 위에서만 실행될 수 있다. 따라서 만들어진 코루틴을 스레드로 보내는 역할을 하는 객체가 필요한 데 이 역할을 바로 CoroutineDispatcher가 한다.
우리가 코루틴을 만들어 CoroutineDispatcher로 코루틴의 실행을 요청하면, CoroutineDispatcher은 자신이 사용할 수 있는 스레드풀의 스레드 중 하나에 코루틴을 보낸다. 이 때 CoroutineDispatcher은 자신이 사용할 수 있는 스레드 풀 내의 스레드 부하 상황에 맞춰 코루틴을 분배한다. 이를 시각적으로 표현하면 다음과 같다.
1. 유저가 코루틴을 생성한 후 CoroutineDispatcher에 전송한다.
2. CoroutineDispatcher은 자신이 잡고 있는 스레드풀에서 사용할 수 있는 스레드가 어떤 스레드인지 확인한 후, 해당 스레드에 코루틴을 보낸다.
3. 분배 받은 Thread는 해당 코루틴을 수행한다.
이는 Executor 프레임웍에서 ExecutorService가 하는 역할과 매우 유사하다.
CoroutineDispatcher 만들기
CoroutineDispatcher 중에서는 사용할 수 있는 스레드가 제한되지 않은 CoroutineDispatcher도 있지만, 대부분의 CoroutineDispatcher은 사용할 수 있는 스레드가 제한되어 있다. 여기서는 사용할 수 있는 스레드가 제한된 CoroutineDispatcher 객체를 만들어보자.
멀티 스레드를 사용할 수 있는 CoroutineDispatcher 만들기
코루틴에서 스레드 풀을 만들기는 쉽다. 단순히 다음과 같은 코드를 수행하는 것만으로 스레드가 3개인 Dispatcher을 생성하는 것이 가능하다.
val dispatcher = newFixedThreadPoolContext(3, "ThreadPool")
단일 스레드를 사용할 수 있는 CoroutineDispatcher 만들기
스레드가 하나인 디스패처는 다음과 같은 방식으로 만들 수 있다.
val dispatcher = newSingleThreadContext("SingleThread")
CoroutineDispatcher는 스레드에 코루틴을 보내는 역할만 한다.
위 그림1~3 에서 볼 수 있듯이 Dispatcher는 코루틴을 스레드에 보내는 역할을 한다. 디스패처의 작업 대기열에 코루틴이 실행 요청되면 해당 CoroutineDispatcher에서 사용할 수 있는 스레드가 있을 때, 코루틴을 해당 스레드로 보내 실행시킨다. 즉, 우리가 CoroutineDispatcher에 코루틴을 보내기만 하면, CoroutineDispatcher은 자신이 사용할 수 있는 스레드가 있을 때 코루틴을 스레드로 보내 실행시킨다.
기본 CoroutineDispatcher
직전 글에서 다룬 coroutine-core 라이브러리와 coroutine-android 라이브러리를 설정하면 미리 정의된 Dispatcher을 사용할 수 있어 newFixedThreadPoolContext나 newSingleThreadContext를 사용해 디스패처를 별도로 생성하거나 정의할 필요가 없다. 기본으로 생성되어있는 디스패처은 다음과 같다.
- Dispatchers.Main - UI와 상호작용하는 작업을 실행하기 위해서 사용되는 디스패처. coroutine-android 라이브러리에 대한 의존성이 있을 때만 사용할 수 있다.
- Dispatchers.IO - 디스크 또는 네트워크 I/O 작업을 실행하는데 최적화되어 있는 디스패처. coroutine-core 라이브러리에 대한 의존성으로만으로도 사용할 수 있다.
- Dispatchers.Default - CPU를 많이 사용하는 작업(CPU 바운드 작업)을 실행하기 위한 디스패처. 정렬 작업이나 JSON 파싱 작업 등을 위해 사용된다. coroutine-core 라이브러리에 대한 의존성만으로도 사용할 수 있다.
미리 정의된 디스패처는 다음과 같이 launch와 함께 사용할 수 있다.
launch(Dispatchers.Main) {
updateButton() // 필요한 Job 수행
}
Kotlin Coroutines 공식 기술 문서 번역이 GitHub 오픈소스로 배포되었습니다. Starganizer가 되어 오픈소스를 지지해주세요.