멀티 프로세스 & 멀티 스레드
참고 링크
1. 멀티 프로세스
멀티 프로세스는 운영체제에서 하나의 응용 프로그램에 대해 동시에 여러 개의 프로세스를 실행할 수 있게 하는 기술을 말한다. 보통 하나의 프로그램 실행에 대해 하나의 프로세스가 메모리에 생성되지만, 부가적인 기능을 위해서 여러개의 프로세스를 생성하는 것이다.
멀티 프로세스 내부를 보면, 하나의 부모 프로세스가 여러 개의 자식 프로세스를 생성하므로 다중 프로세스를 구성하는 구조이다. 한 프로세스는 실행되는 도중 프로세스 생성 시스템 콜(fork) 을 통해 새로운 프로세스들을 생성할 수 있는데, 다른 프로세스를 생성하는 프로세스를 부모 프로세스(Parent Process) 라고 하고, 다른 프로세스에 의해 생성된 프로세스를 자식 프로세스(Child Process) 라고 한다.

부모 프로세스와 자식 프로세스는 각각 고유한 PID(Process ID) 를 가지고 있다. 부모 프로세스는 자식 프로세스의 PID 를 알고 있으며, 이를 통해 주식 프로세스를 제어할 수 있다. 또한, 자식 프로세스는 부모 프로세스의 PID 와 PPID(Parent Process ID) 를 알고 있어, 이를 통해 부모 프로세스와의 통신이 가능하다.
다만, 통신이 가능할 뿐이지, 부모 프로세스와 자식 프로세스는 엄연히 서로 다른 프로세스로 독립적으로 실행되며, 독립적인 메모리 공간을 가지고 있어 서로 다른 작업을 수행한다.
대표적인 예로, 웹 브라우저의 상단 탭(Tab) 이나 새 창을 들 수 있다. 탭 마다 다른 프로세스로 동작하기 때문이다.
1.1 멀티 프로세스의 장점
1.1.1 프로그램 안정성
멀티 프로세스는 각 프로세스가 독립적인 메모리 공간을 가지므로, 한 프로세스가 비정상적으로 종료되어도 다른 프로세스에 영향을 주지 않는다. 그래서 프로그램 전체의 안정성을 확보할 수 있다는 장점이 있다.
예를 들어, 크롬 브라우저에서 여러개의 탭을 띄우고 여러곳의 웹사이트를 방문해 서비스를 이용한다고 하자. 이때 어느 한 탭의 웹사이트가 잘못되어 먹통이 되더라도, 아주 심각한 오류가 아닌 이상 다른 탭은 별 문제없이 이용이 가능하다.
1.1.2 프로그램 병렬성
멀티 프로세스와 여러 개의 CPU 코어를 활용하여 둘의 시너지를 합쳐, 다중 CPU 프로그램에서 각 프로세스를 병렬적으로 실행하여 성능을 향상 시킬 수 있다.
예를 들어, 이미지 처리나 비디오 인코딩 같은 작업을 여러개의 코어나 CPU 에 분산시켜 빠르게 처리할 수 있다.
다만, 이 부분은 멀티 프로세스의 장점이라기 보단, 멀티 프로세스와 멀티 스레드 둘의 장점이 옳다. 그리고 멀티 스레드로 구성하는 것이 멀티 프로세스로 구성하는 것보다 훨씬 효율적이고 빠르기 때문에, 멀티 프로세스로 성능을 올리는 행위는 거의 없다고 보면된다.
1.1.3 시스템 확장성
멀티 프로세스는 각 프로세스가 독립적이므로, 새로운 기능이나 모듈을 추가하거나 수정할 때 다른 프로세스에 영향을 주지 않는다. 그래서 시스템의 규모를 쉽게 확장할 수 있다.
대규모 웹 서비스에서는 수많은 요청을 동시에 처리하기 위해 여러대의 서버를 두고 로드 밸런서와 같은 장비를 사용하여 클라이언트 요청 트래픽을 분산시킨다. 이때 여러대의 서버는 컴퓨터 여러개를 말하는 것일수도 있고, 하나의 성능 좋은 컴퓨터에 여러개의 서버 프로세스를 두는 것을 말하기도 한다. 멀티 프로세스의 상황은 후자이다.
하나의 컴퓨터에 여러개의 서버 프로세스를 띄움으로써 요청을 분산시키는 것을 서버 클러스터(cluster) 라고 한다.
이렇게 멀티 프로세스를 사용하여 여러 대의 서버에 요청을 분산시켜 처리함으로써, 시스템의 규모를 쉽게 확장할 수 있으며, 부가로 서버의 장애나 다운타임을 최소화할 수 있게 된다.
1.2 멀티 프로세스의 단점
1.2.1 Context Switching Overhead
멀티태스킹을 구성하는 핵심 기술인 컨텍스트 스위칭 과정에서 성능 저하가 올 수 있다. 특히나 프로세스를 컨텍스트 스위칭 하면, CPU 에 다음 프로세스의 정보를 불러오기 위해서 현재 프로세스의 PCB 를 저장하고 다음 프로세스의 PCB 를 불러오는 과정을 반복하게 된다.
이 과정에서 CPU 코어의 캐시를 계속 초기화해야 한다.
이로 인한 빈번한 Context Switching 작업으로 인해 비용 오버헤드가 발생할 수 있다. 반면 스레드를 컨텍스트 스위칭하면 프로세스 컨텍스트 스위칭보다 가벼워 훨씬 빠르고 좋다.
따라서 멀티 프로세스 환경에서는 Context Switching Overhead 를 최소화하는 방법이 중요하다. 이를 위해서 프로세스 수를 적정하게 유지하거나, I/O 바운드 작업이 많은 프로세스와 CPU 작업이 많은 프로세스를 분리하여 관리하고, CPU 캐시를 효율적으로 활용하는 등의 방법을 고려해 봐야 한다.
1.2.2 자원 공유 비효율성
멀티 프로세스는 각 프로세스가 독립적인 메모리 공간을 가지므로, 결과적으로 메모리 사용량이 증가하게 된다.
만일 각 프로세스간에 자원 공유가 필요한 경우 프로세스 사이의 어렵고 복잡한 통신 기법인 IPC(Inter-Process Communication) 을 사용하여야 한다.
IPC 란 운영체제 상에서 실행 중인 프로세스 간에 정보를 주고받는 매커니즘을 말한다. 방식으로는 Message Passing, Shared Memory 방식이 있다. 그런데 IPC 자체로 오버헤드(시스템 콜 등등..) 가 발생한다. 또한 코드의 복잡도를 증가시킨다.
2. 멀티 스레드
스레드는 프로세스 내에 있는 실행 흐름이다. 그리고 멀티 스레드는 하나의 프로세스 안에 여러개의 스레드가 있는 것을 말한다. 따라서 하나의 프로그램에서 두가지 이상의 동작을 동시에 처리하도록 하는 행위가 가능해진다.
웹 서버는 대표적인 멀티 스레드 응용 프로그램이다. 사용자가 서버 데이터베이스에 자료를 요청하는 동안 브라우저의 다른 기능을 사용할 수 있는 이유도 바로 멀티 스레드 기능 덕분인 것이다.
즉, 하나의 스레드가 지연되더라도, 다른 스레드는 작업을 지속할 수 있게 된다.
2.1 멀티 스레드의 장점
윈도우, 리눅스 등 많은 운영체제들이 멀티 프로세싱을 지원하고 있지만, 멀티 스레딩을 기본으로 하고 있다.
왜 멀티 프로세스보다 멀티 스레드로 프로그램을 돌리는 것이 유리한지 그 이유에 대해서 알아보자.
2.1.1 스레드는 프로세스보다 가벼움
일단 스레드는 프로세스보다 용량이 가볍다. 그도 그럴게 스레드는 프로세스 내에서 생성되기 때문에, 스레드의 실행 환경을 설정하는 작업이 매우 간단하며 생성 및 종료가 빠르다. 또한, 스레드는 프로세스와 달리, 코드, 데이터, 힙 영역을 제외한 나머지 자원을 공유하기 때문에, 기본적으로 내장되어 있는 데이터 용량이 프로세스보다 당연히 적다.
그래서 스레드를 생성하고 제거할 때, 프로세스 내부의 자원만을 관리하면 되기 때문에 프로세스 생성, 제거 보다 훨씬 빠른것이다.
2.1.2 자원의 효율성
멀티 스레드는 하나의 프로세스 내에서 여러 개의 스레드를 생성되기 때문에, heap 영역과 같은 공유 메모리에 대해 스레드 간에 자원을 공유가 가능하다. 이를 통해, 프로세스 간 통신(IPC) 을 하지 않고도 데이터를 공유할 수 있기 때문에, 자원의 효율적인 활용이 가능해 시스템 자원 소모가 줄어든다.

2.1.3 Context Switching 비용 감소
스레드에도 컨텍스트 스위칭 오버헤드가 존재한다. 하지만 상대적으로 프로세스 컨텍스트 스위칭 오버헤드보다 훨씬 낮아 비용이 낮다는 장점이 있다.
프로세스 컨텍스트 스위칭 비용은 스위칭 할 때마다 CPU 캐시에 있는 내용을 모두 초기화하고, 새로운 프로세스 정보를 CPU 캐시에 적재해야 하므로 높은 비용이 든다. 반면 스레드 컨텍스트 스위칭 비용은 스위칭할 때 스레드 간에 공유하는 자원을 제외한 스레드 정보(stack, register) 만을 교체하면 되므로 프로세스 컨텍스트 스위칭 비용보다 상대적으로 낮은 것이다.
2.1.4 응답 시간 단축
앞의 멀티 스레드의 장점을 종합해보자면, 멀티 스레드는 스레드 간의 통신이나 자원 공유가 더욱 용이하며, 프로세스보다 가벼워 컨텍스트 스위칭 오버헤드도 작다. 따라서 멀티 프로세스보다 응답 시간이 빠르다.
이러한 이유로 멀티 프로세서 환경에서 멀티 스레드를 사용하여 작업을 처리하는 것이 멀티 프로세스를 사용하는 것보다 더 효율적이다라고 말할 수 있다.
2.2 멀티 스레드의 단점
2.2.1 안정성 문제
멀티 프로세스 모델에서는 각 프로세스가 독립적으로 동작하므로 하나의 프로세스에서 문제가 발생하도 다른 프로세스들은 영향을 받지 않기 때문에, 프로그램이 죽지 않고 계속 동작할 수 있다. 그러나 멀티 스레드 모델 에서는 기본적으로 하나의 스레드에서 문제가 발생하면 다른 스레드들도 영향을 받아 전체 프로그램이 종료될 수 있다.
물론 이는 프로그래머의 역량에 따라 극복할 수가 있다.
예를 들어, 스레드에 에러가 발생하는 경우 이에 대한 적절한 예외 처리를 잘 해놓는다던지, 에러 발생 시 새로운 스레드를 생성하거나 스레드 풀(Thread Pool) 에서 잔여 스레드를 가져오던지 하여 프로그램 종료를 방지할 수 있다.
다만 이때, 새로운 스레드 생성이나 놀고 있는 스레드 처리에 추가 비용이 발생하게 된다.

2.2.2 동기화로 인한 성능 저하
멀티 스레드 모델은 여러 개의 스레드가 공유 자원에 접근할 수 있기 때문에, 동기화 문제가 발생할 수 있다.
예를 들어, 여러 스레드가 동시에 한 자원을 변경해 버린다면, 의도하지 않은 동작이 일어나 치명적인 버그가 발생할 수 있다. 따라서 스레드 간 동기화(synchronized) 는 데이터 접근을 제어하기 위한 필수적인 기술이다.
동기화 작업은 여러 스레드들이 자원에 대한 접근을 순차적으로 통제하는 것이다. 그러면 동시 접근으로 인한 동시 수정과 같은 현상은 일어나지 않게 된다. 그러나 동기화 작업은 여러 스레드 접근을 제한하는 것이기 때문에, 병목 현상이 일어나 성능이 저하될 가능성이 높아진다는 단점이 있다.
이를 해결하기 위해서 임계 영역(Critical Section) 에 대해 뮤텍스(Mutex), 세마포어(Semaphore) 방식을 활용한다.

2.2.3 데드락(교착 상태)
Deadlock 이란, 다수의 프로세스나 스레드가 서로 자원을 점유하고, 다른 프로세스나 스레드가 점유한 자원을 기다리는 상황에서 발생하는 교착상태를 의미한다. 여러 개의 스레드가 서로 대기하면서 무한정 기다리게 되는 무한 루프와 같은 증상으로 생각하면 된다.
예를 들어, 스레드 1은 자원 A 를 점유하고 있는 상태에서 자원 B 가 필요한 상황이다. 그리고 스레드 2 는 자원 B 를 점유하고 있는 상태에서 자원 A 가 필요한 상황이다. 하지만 스레드 1은 자원 B 가 필요한 상황에서 자원 A 를 빌려줄 수 있는 상황이 아니고, 스레드 2 또한 자원 A 가 필요한 상황에서 자원 B 를 빌려줄 수 있는 상황에 아니다.
이처럼 다수의 스레드가 같은 lock 을 동시에, 다른 명령에 의해 획득하려 할 때 서로 절대 불가능한 일을 계속적으로 기다리는 상황을 의미한다.

다만, 데드락은 멀티스레드만의 단점이라고 보다는 멀티 프로세스와 스레드 모델의 공통된 문제점이라고 말하는 것이 옳다. 왜냐하면 프로세스 끼리는 기본적으로 독립적인 메모리 공간이지만 IPC 를 통해 공유 자원을 사용할 수 있기 때문에, 멀티 스레드와 똑같이 데드락 상황에 빠질 수 있다.
2.2.4 Context Switching Overhead
앞서 멀티 프로세스보다 멀티 스레드의 컨텍스트 스위칭 오버헤드가 작아 성능에 유리하다고 표현했다. 하지만 컨텍스트 스위칭 오버헤드 비용 자체를 무시할 수는 없다. 특히나 스레드 수가 많으면 많을수록 그 만큼 컨텍스트 스위칭이 많이 발생하고 당연히 이는 성능 저하로 이루어진ㄴ다.
이 부분은 '스레드를 많이 쓸수록 항상 성능이 좋아질까?' 라는 물음으로 던져질 수 있다.
이에 대한 답변을 상황별로 구분할 수 있어야 한다.
Last updated