깨알 개념/Kotlin

[Kotlin] Couroutine - 스레드(Thread)와 스레드 풀(Thread Pool)

interfacer_han 2024. 2. 15. 12:19

#1 스레드 (Thread)

#1-1 개념

다른 용어들과의 관계를 통해 '스레드'라는 개념의 윤곽을 잡는다.


#1-2 스레드의 실시간성

이 예시 도식도에서 시점 A에서와 시점 B에서의 스레드는 각각 1개와 2개와 그 갯수가 서로 다르다. 프로세스는 프로그램의 실행 중인 인스턴스이기 때문에, 스레드는 실시간성을 지닌다. 예를 들어, 사람을 프로세스라고 비유해보겠다. 통화를 하면서 요리를 하는 사람은 2개의 병렬 스레드를 지니고 있다고 볼 수 있다. 그러다가 통화가 종료되어 요리에만 집중하면, 그 사람은 요리라는 단일 스레드만 있는 프로세스가 된다. 이와 같이 프로세스가 어느 시점 어느 순간에 있느냐에 따라서 스레드의 갯수는 얼마든지 변할 수 있다.

 

#2 스레드 풀 (Thread Pool)

#2-1 개념

프로그램이 명령어의 집합이듯, 스레드의 집합은 스레드 풀이다. 하지만 "명령어를 모아 프로그램을 만든다"는 말은 그럴듯해도, "스레드를 모아 스레드 풀을 만든다"는 말은 어색하다. 왜냐하면, 스레드는 스레드 풀로부터 만들어지기 때문이다. 즉, 선후관계가 반대다. 프로세스는 스레드 풀에게 스레드를 '요청'한다. 스레드 풀은 어떤 한 스레드를 '할당'한다. 그 할당된 스레드의 쓰임이 다하면, 다시 스레드 풀로 '반환'된다. 스레드 풀의 이름에 풀(Pool)이 들어가 있는 이유기도 하다. Pool의 사전적 의미는 웅덩이, 모으다, 고여 있는 곳 따위다. 스레드 풀로부터 스레드를 할당받는 것은 웅덩이에서 뭔가를 꺼내오는 것으로 비유할 수 있다.

 

Coroutine에서 스레드를 할당받는 순간은 Coroutine builder를 사용하는 순간이다 (CoroutineScope를 사용하는 순간이 아니다. CoroutineScope는 Coroutine builder의 환경 설정에 불과하다). 그리고 그 Builder가 종료되면, 자동으로 반환된다.

 

#2-2 단일 스레드만이 존재하는 스레드 풀 - Dispatchers.Main

안드로이드의 Dispatchers.Main은 마치, 단일 함수가 본체지만 형태는 인터페이스인 SAM과 비슷하다. Dispatchers.Main은 형태만 스레드 풀이고, 사실은 단일 스레드다. 1개의 스레드만이 할당 및 반환되므로, Dispatchers.Main 스레드 풀에 여러가지 일을 시키면 절대로 병렬적으로 실행되지 않고, 요청한 순서대로 직렬(순차)적으로 실행된다.

 

다행히, 안드로이드의 Dispatchers.Main은 Block 또는 Suspend가 원천적으로 불가능하다. 그렇게 설계된 이유는 안드로이드에서는 메인 스레드(Main Thread)에서 네트워크 요청이나 파일 입출력 등과 같은 UI 외적인 작업을 수행하면 앱의 응답성이 떨어지기 때문이다. 따라서 Dispatchers.Main에 여러가지 일을 시켜서 앱이 버벅이는(?) 걸 보고 싶다면, runBlocking이나 Job.join()으로는 불가능하고 그냥 Main 스레드에 일을 무식하게 많이 시키면 된다. 그 예는 이 게시글의 #2-3에 있다.

 

#3 요약

스레드는 흐름이고, 스레드 풀(Pool)로부터 할당된다.