멀티 스레드
멀티스레드 프로그래밍이란 작업을 실행하는 단위인 스레드를 여러 개 사용해 동시에 여러 일을 한꺼번에 처리하는 프로그램을 작성하는 걸 의미한다.
사용 이유와 단점
일단 멀티스레드가 필요한 대표적인 상황은 아래와 같다 (물론 비동기 프로그래밍으로도 가능!)
-
오래 걸리는 하나의 작업 + 빨리 끝나는 여러 작업을 동시에 처리
-
처리가 느린 작업 동안 처리가 짧은 일을 동시에 처리
-
기기에 있는 CPU 자원을 모두 활용해야할 때
이를 싱글 스레드를 사용한다는 가정으로 게임 서버에서 예를 들자면
-
플레이어 정보를 디스크에 기록하는 시간은 대략 1/10,000초 정도
(=> 디스크 접근 작업은 초당 10,000번 이상의 요청은 처리하지 못한다는 의미 ) -
만약 1만 대가 넘는 클라이언트가 동시에 플레이어 정보를 액세스하기 위해 요청을 한다면?
-
쌓인 만큼의 작업을 초당 10,000개씩만 처리하기때문에 UX가 매우 떨어진다..!
(클라이언트가 정보만 액세스하는게 아니라 다른 요청도 하잖아요..)
위와 같은 상황에서 작업을 할 수 있는 스레드가 여러 개라면 동시 처리 가능한 작업 수가 증가하게 된다!
그럼 멀티스레드의 단점은 없는걸까..? 당연히 아니다.
-
똑같은 연산을 하더라도 속도가 더 느려질 수 있음
(컨텍스트 스위칭 오버헤드) -
실수를 조금만 하여도 크리티컬한 오류를 불러오기 쉬움
-
디버깅 시, 시작 지점이 여러 개 이므로 난이도가 높음
등등에 공유 자원에 관한 생각을 더 많이 해야되는 것도 있다!
(Do you Know DEADLOCK!?)
임계 영역(Critical Section)과 Mutex(Mutual Exclusion)
동기화를 위해 사용되는 개념으로 사실 임계 영역과 뮤텍스(상호 배제)는 같은 의미로 사용된다!
그래서 뮤텍스란 결국 스레드가 독점해서 사용할 특정 영역을 뜻한다! 여기서 독점을 하는 행동을 Lock 이라 일컫는다.
// 임계 영역을 만들어 잠그고 로직을 실행
// 내부에서 작업을 마치면 자동으로 언락해준다!
object mx = new object();
lock(mx)
{
read(x);
write(y);
sum(x);
}
- 뮤텍스를 사용할 때 주의할 점은 영역의 크기와 잠금 순서이다!
코드에서 뮤텍스의 크기를 너무 크게 잡으면 하나의 스레드가 작업을 할 동안 다른 스레드는 작업을 못하기에 의미가 없고,
너무 작게 잡으면 뮤텍스에 액세스 하는 오버헤드가 증가하여 오히려 느려진다..
또한 잠금 순서를 주의해야하는 일관성 없는 잠금 순서는 교착 상태(Dead Lock)에 빠지기 쉽기 때문이다. (교착 상태는 두 개 이상의 스레드가 서로 잠금을 걸어둔 턱에 필요한 자원(뮤텍스)을 무한정 기다리는 상태를 뜻한다!)
- 추가로 Mutex 에서 접근 가능 스레드 수를 늘린 걸 세마포어(Semaphore) 라 한다!
시리얼 병목(Serial Bottleneck)
여러 CPU가 각 스레드의 연산을 실행해 동시 처리량을 올리는 것을 병렬성(Parallelism)이라 하고,
이러한 병렬성이 제대로 나오지 않는 현상을 시리얼 병목(Serial Bottleneck)이라 한다.
뮤텍스를 사용해 멀티 스레드간 동기화를 성공하였어도, 뮤텍스로 인해 CPU가 노는 시간이 생긴다..
이처럼 CPU가 늘어날 수록 총 처리 효율성이 떨어지는 현상으로 암달의 저주(Amdahl’s Law)라고 한다.
스레드 풀링(Thread Pooling)
멀티 스레드를 이용해 게임 서버를 구축한다면 스레드의 갯수를 어떻게 정해주어야 할까?
작업을 하는 서버의 스레드를 클라이언트 하나당 배치해주면 쉬워 보이지만,
스레드의 호출 스택을 저장할 메모리 공간과 클라이언트의 수와 요청량의 증가에 따라 컨텍스트 스위칭 비용이 많이 들게 된다..
그렇기에 스레드를 효율적으로 재사용하는 방식인 스레드 풀링 기법을 게임 서버에선 주로 사용한다!
그렇다면 다시 질문으로 돌아가 스레드의 갯수는 몇 개로 정해주는게 좋은가?
-
주 역할이 CPU 연산만 하는 스레드라면 스레드 갯수는 서버의 CPU와 동일하게 잡는다!
-
디바이스 타임(DB나 파일 액세스 등의 처리에 필요한 시간)이 생기는 작업이 많은 경우 CPU 러닝 타임을 프로파일링하여 스레드 갯수를 CPU 갯수보다 늘린다!
한줄 평
- 성장 진행중