(Kotlin Coroutine) Dispatchers
Dispatcher란?
The coroutine dispatcher can confine coroutine execution to a specific thread, dispatch it to a thread pool, or let it run unconfined.
즉 코루틴이 어떤 thread(thread pool) 위에서 실행될지를 결정하는 역할.
기본 제공 Dispatchers
- https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/
- 기본 제공 Dispatchers 상세 설명과 예제
- https://kotlinlang.org/docs/coroutine-context-and-dispatchers.html#dispatchers-and-threads
- 메인에서 Dispatcher 지정 없이
runBlocking
하면 main thread 위에서 수행.
- 직접 ThreadPool 생성해서 전용 Dispatcher를 정의 할 수도 있다. (하단 참조)
Dispatchers.Default
- The default CoroutineDispatcher that is used by all standard builders like launch, async, etc if no dispatcher nor any other ContinuationInterceptor is specified in their context.
- CPU core 수와 동일한 스레드 수로 구성된 스레드풀. core가 1개인 경우는 2개로 구성.
- CPU bound 작업에 사용.
Dispatchers.IO
- IO bound 작업에 사용.
- This dispatcher shares threads with a
Default
dispatcher, so usingwithContext(Dispatchers.IO) { ... }
does not lead to an actual switching to another thread — typically execution continues in the same thread. 👍 (thread switching은 비싸기 때문에. 최소화 하는 것이 좋다.)
Dispatchers.Main
(MainScope()
)
- 안드로이드 같은 UI 포함된 개발에서 사용. BE 개발에서는 쓸 일이 없음.
- UI 관련 동작하는 Main thread에서 돌아가도록 한정 할 때 사용.
- e.g., 화면 표시를 담당하는 Activity가 종료되는 경우 관련 코루틴들을 한꺼번에 종료해야 할 때
Dispatchers.Unconfined
- A coroutine dispatcher that is not confined to any specific thread. It executes initial continuation of the coroutine in the current call-frame and lets the coroutine resume in whatever thread
thread pool 고갈 방지 (직접 thread pool, Dispatcher 생성)
- 예를 들어 DB library가 coroutine 지원하지 않아 blocking call 인 경우, thread pool의 모든 thread가 block되어 새로운 request를 처리 할 수 없게 되는 상황을 방지해야 한다.
Dispatchers.IO
에 던지는 것으로 시스템 전체가 block 되는 것은 막을 수 있다. 하지만, DB call로 인해Dispatchers.IO
스레드 풀 전체가 block 되면,Dispatchers.IO
를 사용하는 다른 작업(e.g., HTTP call)들도 영향을 받는다.
IO 풀에서 최대 쓸 수 있는 스레드 수 제한
Dispatchers.IO
스레드 풀을 share 해서 쓰면서, 최대 쓸 수 있는 스레드 수를 제한 할 수 있다.- https://github.com/Kotlin/kotlinx.coroutines/issues/2919
1
private val myDatabaseDispatcher = Dispatchers.IO.limitedParallelism(10) // At most 10 connections to the database
아예 thread pool을 완전히 분리
- 또는 절대 밀리면 안되는 코어한 작업이라, 다른 작업으로 인한 영향을 아예 제거하고 싶을 수도 있다. (다른 작업으로 인해 IO 스레드풀이 고갈될 가능성도 있으므로)
- 이런 경우 전용 스레드풀로 완전히 분리하는게 안전하다
newScheduledThreadPool()
1
2
3
private val coreWorkDispatcher = newFixedThreadPoolContext(10)
is equivalent to
private val coreWorkDispatcher = Executors.newScheduledThreadPool(10).asCoroutineDispatcher()
delay
같은 기능의 built-in yield support를 위해서는newScheduledThreadPool()
여야 한다.- If the given ExecutorService is an instance of ScheduledExecutorService, then all time-related coroutine operations such as delay, withTimeout and time-based Flow operators will be scheduled on this executor using schedule method
newFixedThreadPool()
1
private val coreWorkDispatcher = Executors.newFixedThreadPool(10).asCoroutineDispatcher()
- 대부분의 경우는
newScheduledThreadPool()
사용하면 되는데, - 만약 coroutine 스케줄링과 무관한, standard JDK executors 기반의 스레드 스케줄링 정책으로 돌아가는 스레드풀을 만들고 싶다면,
newFixedThreadPool
사용해야 한다.
This post is licensed under CC BY 4.0 by the author.