시배's Android

Kotlin Coroutines Deep Dive | 12장. 디스패처 본문

Book/Kotlin Coroutines Deep Dive

Kotlin Coroutines Deep Dive | 12장. 디스패처

si8ae 2024. 2. 5. 22:17

기본 디스패처

  • 디스패처를 설정하지 않으면 기본적으로 설정되는 디스패처는 CPU 집약적인 연산을 수행하도록 설계된 Dispatchers.Default 입니다.
  • 실행되는 컴퓨터의 CPU 개수와 동일한 수의 스레드 풀을 가지고 있습니다.
  • Dispatchers.Default의 limitedParallelism을 사용하면 디스패처가 같은 스레드 풀을 사용하지만 같은 시간에 특정 수 이상의 스레드를 사용하지 못하도록 제한할 수 있습니다.

메인 디스패처

  • 안드로이드에서 메인 스레드는 UI와 상호작용하는 데 사용하는 유일한 스레드입니다.
  • 메인 스레드가 블로킹되면 전체 애플리케이션이 멈춰 버립니다.
  • 메인 스레드에서 코루틴을 실행하려면 Dispatchers.Main을 사용하면 됩니다.

IO 디스패처

  • Dispatchers.IO는 파일을 읽고 쓰는 경우, 안드로이드의 sharedpreference를 사용하는 경우, 블로킹 함수를 호출하는 경우처럼 IO 연산으로 스레드를 블로킹할 때 사용하기 위해 설계되었습니다.
suspend fun main() {
	val time = measureTimeMillis {
    	coroutineScope {
        	repeat(50) {
            	lauch(Dispatchers.IO) {
                	Thread.sleep(1000)
                }
            }
        }
    }
}
  • 처음에는 풀이 비어 있지만 더 많은 스레드가 필요해지면 스레드가 생성되고 작업이 끝날 때까지 활성화된 상태로 유지됩니다.
  • Dispatchers.Default는 프로세서가 가지고 있는 코어 수로 제한이 됩니다.
  • Dispatchers.IO는 64개로 제한이 됩니다.
  • withContext(Dispatchers.IO)로 래핑한 함수가 너무 많은 스레드를 블로킹하면 문제가 될 수 있습니다.

커스텀 스레드 풀을 사용하는 IO 디스패처

  • 너무 많은 스레드는 자원을 비효율적으로 사용합니다. 
  • 스레드 수가 적다면 사용 가능한 스레드를 기다리게 되므로 성능상 좋지 않습니다.
  • 가장 중요한 건 이때 사용하는 스레드 한도가 Dispatchers.IO를 비롯한 다른 디스패처와 무관하다는 사실입니다.

싱글스레드로 제한된 디스패처

  • 다수의 스레드를 사용하는 모든 디스패처에서는 공유 상태로 인한 문제를 생각해야 합니다.
  • 디스패처가 스레드 하나를 액티브한 상태로 유지하고 있으며, 더 이상 사용되지 않을 떄는 스레드를 반드시 닫아야 한다는 문제점이 있습니다.
  • 최근에는 Dispatchers.Default나 병렬 처리를 1로 제한한 Dispatchers.IO를 주로 사용합니다.

제한받지 않는 디스패처

  • Dispatchers.Unconfined
  • 디스패처는 스레드를 바꾸지 않는다는 점에서 이전 디스패처들과 다릅니다.
  • 제한받지 않는 디스패처는 단위 테스트할 때 유용합니다.
  • launch를 호출하는 함수를 테스트해야 된다고 생각해 봅시다.
  • 시간을 동기화하는 건 쉽지 않습니다.
  • 이런 경우 Dispatchers.Unconfined로 다른 디스패처를 대체하여 사용할 수 있습니다.
  • 모든 스코프에서 제한받지 않는 디스패처를 사용하면 모든 작업이 같은 스레드에서 실행되기 때문에 연산의 순서를 훨씬 쉽게 통제할 수 있습니다.
  • 성능적인 측면에서 보면 스레드 스위칭을 일으키지 않는다는 점에서 제한받지 않는 디스패처의 비용이 가장 저렴합니다.

메인 디스패처로 즉시 옮기기

  • 코루틴을 배정하는 것에도 비용이 듭니다.
  • withContext가 호출되면 코루틴은 중단되고 큐에서 기다리다가 재개됩니다.
  • Dispatchers.Main.immediate가 있습니다.
  • 메인 스레드에서 다음 함수를 호출하면 스레드 배정 없이 즉시 실행됩니다.