본문 바로가기

CS 과목(CS科目)/운영체제(OS)

스레드 풀(Thread Pool)은 왜 쓰는 걸까?? 어떻게 쓰는 게 잘 쓰느는 걸까??

API 서버의 스레드 모델

위와 같이 서버의 각 Request마다 1개의 스레드를 만들어서, 응답을 하게 하는 스레드 모델이 있다고 하자.

이때, 한 가지 짚고 넘어 가야 할 issue가 있다.

만약 thread per request 모델의 동작 방식이 서버에 들어 오는 요청마다 스레드를 새로 만들어서 처리하고 처리가 끝난 스

레드는 버리는 식으로 동작한다면 어떻게 될까??

-> 당연히 스레드 생성에 소요되는 시간 때문에 요청 처리가 더 오래 걸릴 것이다

( 스레드는 OS Kernel level에서 생성이 되는 것이다. user mode는 단순히 프로세스/스레드를 실행하는 mode지만, kernel mode는 우리가 이전 시간에서 살펴 보았듯이 문맥 교환 등의 여러 추가적인 비용이 많이 드는 작업이다.)

 

 

SOLUTION : Thread Pool

Thread Pool

Thread Pool의 동작 흐름

1. 스레드 풀에 먼저 적절한 개수의 스레드를 미리 생성을 해 놓는다.

2. Request가 오면 스레드 풀 안에 존재하는 Queue에 담긴다.

3. Queue안의 Request를 놀고 있는 스레드와 매핑을 시켜 준다.

4. 스레드가 요청을 처리하고 나면, 스레드가 해제되는 것이 아니라 스레드 풀에서 다시 재사용 됨.

 

Thread Pool을 사용하는 경우 : 여러 작업을 동시에 처리해야 할 때

1. Thread per Request Model

2. task을 subtask로 나뉘어서 동시에 처리

-> 예를 들어, 1000억 개의 item의 가격을 합하는 task가 있다고 하자.

이것을 순차적으로 1000억 번 훓어서 계산할 수도 있지만, 1000억 개의 몇 개의 부분으로 나누어서 동시에 합할 수도 있다. 

3. 순서 상관없이 동시 실행이 가능한 task 처리

-> 예를들어, 방을 청소하는 task가 있다고 하자. 

그 task에는 1. 바닥 닦기 2, 유리 닦기 3. 빗자루질 하기 작업들이 있다.

1,2,3은 굳이 순서를 지킬 필요가 없기 때문에 동시에 실행시켜도 상관이 없다. 

 

Thread Pool 사용 TIP

1. 스레드 풀에 몇 개의 스레드를 만들어 주는 게 적절한 가?

-> cpu의 코어 개수와 task의 성향에 따라 다름.  

 

2. 스레드 풀에서 실행될 task 개수에 제한이 없다면(요청이 미친듯이 몰려올 수 있다면) , 스레드 풀의 큐가 사이즈 제한이 있는지 꼭 확인할 것!

스레드 풀에 100개의 스레드가 있다고 하자.

100개의 요청이 들어와서 큐에 들어 가면, 100개의 스레드가 모두 사용되고 있을 것이다.

이 와중에 요청이 계속해서 무한정으로 들어오면 큐에 일단 그 요청들이 쌓일 것이다.

그러나 이것은 잠재적으로 메모리를 고갈시킬 것이다. 

고로, 큐의 사이즈를 확인을 하고, 큐가 다 차면 안타깝지만 새로 들어오는 요청들을 버려든지 해야 한다. 

 

이 때, 스레드 풀의 큐 사이즈가 어떻게 되는지 소스 코드를 까보자.

매개변수 capacity가 큐의 사이즈가 되고, 그 값은 Integer.Max_VALUE(=약 20억)이다.

번외로 파이썬의 스레드 풀 코드도 살펴보자.

파이썬의 디폴트 큐 사이즈는 무한이다. 

 

pool이라는 개념은 스레드에만 쓰이는 것이 아니다.

1. connection pool

-> TCP/IP 연결에는 초기에 시간 비용이 많이 든다. 미리 Connection을 만들어 Pool에 집어 넣어서, 연결을 할 때마다 가져다 씀으로서 초기 연결 비용을 줄일 수가 잇다.

2. process pool

-> 프로세스를 미리 만들어 놓음. 

3. objective pool 

-> 게임에서 주로 많이 쓰는 기법이며, 자주 사용되는 메시들을 pool에 넣어 놓는다.

등 많은 pool이 존재한다. 

(참고로, 리눅스에서는 스레드가 많을수록 문맥 교환이 더 자주 일어난다.)