본문 바로가기
오늘은 뭘 배울까?/Android

Coroutine Dispatcher, 넌 대체 뭐야?

by Kim Juhwan 2022. 8. 31.

🚀 글 읽는 순서 🚀

코루틴은 왜 빠른 걸까요?
suspend 함수란 무엇인가요?
-> Coroutine Dispatcher, 넌 대체 뭐야? (현재)
1. 요약
2. Dispatcher
    2-1. 개념
    2-2. 종류
    2-3. 사용법
3. Default와 IO의 차이
4. 의문점

 

 

 


 

 

1. 요약

🧑‍💻: Dispatcher는 무엇이며 종류가 어떻게 되나요?

 

👨🏻‍🦱: Dispatcher는 상황에 맞게 스레드 풀 내의 스레드에게 코루틴을 배분하는 역할을 합니다.
Default, IO, Main이 있습니다. (Unconfined는 논외로 하겠습니다)

 

* 참고로 저도 공부하면서 정리한 글이기 때문에 잘못된 부분이 있을 수 있습니다. 지적 많이 부탁드려요 ( _ _)

 

2. Dispatcher

2-1. 개념

구글에 디스패치를 검색해보자

 

오늘 배울 내용은 Coroutine의 dispatcher !

우선 dispatch가 뭔지 검색을 해볼까나... 🤔

 

네가 왜 거기서 나와

 

디스패치를 검색하니 (파파라치로 유명한...) 연예뉴스 디스패치가 나왔다.

대체 Dispatch가 무엇이길래??

 

 

Dispatch는 위와 같은 뜻이 있다.

연예계 소식을 취재하기 위해 기자들을 보내고 파견하는 디스패치를 떠올리면

의미가 쉽게 와닿을 것이다.

 

Coroutine, Dispatcher, Thread의 관계

 

Coroutine에서의 Dispatcher도 똑같다.

Coroutine을 어떤 Thread에게 보낼지 정하는 놈을 Dispatcher라고 한다.

 

참고로 Thread Pool은 스레드를 정해진 개수만큼 정해놓고 작업 큐에 들어오는 작업들을 하나씩 처리한다.

매번 스레드를 생성했다가 지웠다가 하는 게 아니라 일정 개수만큼 만들어 놓는 것이다.

 

 

Dispatcher는 Thread Pool 안에서 탱자탱자 놀고 있는 스레드를 찾아 Coroutine을 배분한다.

-> 조금 고급지게(?) 말하면 스레드 풀 내의 스레드 부하 상황에 맞게 코루틴을 배분한다고 할 수 있다.

 

이것이 Dispatcher의 간략한 개념이다.

 

2-2. 종류

Dispatcher에도 종류가 있다.

네트워크 통신을 할 때 사용하는 거, 무거운 연산은 할 때 사용하는 거 등...

상황에 맞게 사용해야 하기 때문에 그 종류를 알아보자.

 

  • Default
    • 리스트를 정렬하거나, Json  Parsing 작업 등에 최적화되어 있다.
    • 무거운 연산 작업에 최적화되어 있다. (CPU를 많이 사용하는 작업)
    • CPU 개수만큼 스레드를 생성해 작업한다.
  • Main
    • 화면 UI 작업을 하기 위해 사용
  • IO
    • 네트워크, DB 작업 등에 최적화 되어 있다.
    • 읽기, 쓰기 작업에 최적화
    • 스레드를 block 할 필요가 있을 때 사용
    • 기본적으로 최대 64개의 Thread를 생성할 수 있다. (Custom 하여 늘릴 수 있음)

 

위 설명을 참고해 상황에 맞는 Dispatcher를 사용해주면 된다.

그러면 코루틴의 실행을 특정 스레드에 국한시켜주게 된다고 한다.

 

2-3. 사용법

CoroutineScope(Dispatchers.IO).launch {
	// 코루틴이 실행할 작업
}

아주 간단하다.

CoroutineScope의 인자로

Dispatchers.IO

Dispatchers.Default

Dispatchers.Main을 선택해서 넣어주면 된다.

 

3. Default와 IO의 차이

[목차 2-2]에서 설명했듯이 Default는 무거운 연산 작업에 최적화되어있고

IO는 네트워크나 DB같은 읽기 쓰기 작업에 최적화되어있다.

상황에 맞게 사용해야 하는 건 알겠는데

내부적으로 무슨 일이 벌어지고 있기에 차이가 있는 걸까?

 

나는 처음에는 스레드가 각자 특성이 있어서 잘하는 일이 나뉘는 줄 알았다.

사람도 축구 잘하는 사람이 있고 농구 잘하는 사람이 있듯이

스레드도 IO 작업을 잘하는 스레드, DB 작업을 잘하는 스레드가 있는 줄 알았다.

 

근데 사실 IO Dispatecher와 Default Dispatcher는 같은 스레드를 공유하기 때문에

스레드 자체는 똑같다고 볼 수 있다.

다만 스레드 개수에서 차이가 있는데, 이에 대해 자세히 알아보자.

 

코어와 스레드의 관계

 

보통 한 개의 코어는 하나의 스레드를 처리한다. (하이퍼스레딩 개념은 논외로 했을 때)

회사원 1명이 1개의 작업을 처리한다고 비유를 들어보자.

 

 

만약 job1과 job2가 너~~무 쉬운 일이어서

왔다 갔다 번갈아 가며 동시에 처리할 수 있다고 치자.

 

 

그러면 회사원이

"음.. 내가 job1을 여기까지 작업을 했으니 메모해둬야지"

"그다음에 job2는 어디까지 했더라?"

하면서 진행 중이던 작업을 기록해두고 다음에 진행할 작업을 다시 불러오는 작업이 필요하게 된다.

이렇게 작업을 전환하는 것을 Context Switiching(문맥 교환)이라고 하고

이때 낭비되는 시간을 오버헤드라고 한다.

 

다시 본론으로 돌아와 Default Dispatcher를 생각해보자.

코어 개수만큼의 스레드를 사용한다고 한다.

만약, 코어보다 더 많은 스레드를 사용하면? 오버헤드가 발생하게 된다.

그래서 최대 개수를 CPU 코어 개수만큼으로 제한을 두고 사용하는 전략을 쓰는 것이다.

회사원 1명에게 1개의 작업만 시킨다고 보면된다. 어려운 일(무거운 작업)이니 이거에만 집중해!

(여담으로 컴퓨터 살 때 스레드가 많다고 해서 무조건 좋은 게 아니라고 한다. 코어보다 살짝 많은 게 좋은 거라고... 참고)

 

반면, IO Dispatcher는 대기시간이 있는 작업들을 수행하기 위해 쓰인다.

(네트워크, DB 등...)

thread가 blocking 되기 때문에 더 많은 스레드를 사용하여 병렬 처리를 하는 것이 효율적이기 때문에

IO Dispatcher는 보다 더 많은 개수의 스레드를 생성해 사용하는 전략을 쓰는 것이다.

 

4. 의문점

suspend fun main() = coroutineScope {
    repeat(1000) {
        launch { // or launch(Dispatchers.Default) {
            // To make it busy
            List(1000) { Random.nextLong() }.maxOrNull()

            val threadName = Thread.currentThread().name
            println("Running on thread: $threadName")
        }
    }
}

그럼 Default가 진짜 CPU 코어 수만큼 스레드가 생성되는지 확인해보자.

위 코드를 돌려보면...

 

작업관리자 - 성능에서 코어 수와 논리 프로세서(스레드)의 수를 확인할 수 있다.

 

엥!!?

코어 수만큼 생성한다면서 스레드 수만큼 생성되는 걸 확인할 수 있었다.

분명 공식문서에서도 코어 개수만큼 이랬는데...

 

이에 대해서 확실한 답을 찾진 못했지만

추측컨데, 하이퍼스레딩이라는 기술 때문인듯하다.

하나의 코어에서 둘 이상의 스레드를 실행하는 기술이고

이 기술이 적용된 컴퓨터는 논리 프로세서를 기준으로 봐야 하는 것 같다.

(불확실한 정보이니 참고만)

 

아시는 분 계시면 댓글 좀...

 

 


💡 느낀 점

  • 스레드 수 말고 더 다른 차이점이 있나 찾아보고 싶었는데 못 찾았다. 더 low 하고 내부적인 로직을 알고 싶은데... 끙
  • Dispatcher가 Rx의 Scheduler와 비슷하다는데, Rx도 언제 한 번 깊게 파봐야겠다.
  • 메인 스레드는 하나뿐인데 이걸 굳이 담당하는 Dispatcher가 있는 이유는 withContext로 코루틴이 돌아가는 환경을 변경할 때 필요한 걸까??? 흠 잘 모르겠다. 다음 포스팅은 withContext로 결정.

📘 참고한 자료


 

 

반응형

댓글