본문으로 바로가기

노드가 싱글 스레드이기 때문에 가급적 동기적으로 함수를 짜서는 안된다는 것은 노드를 다루면 처음에 배우는 내용이다. 도대체 그 '스레드'가 무엇인지 알기 위해서는 프로그램  => 프로세스 => 스레드로 연결되는 흐름을 알 필요가 있다.

 

 

💻 프로세스

 

여기서 프로그램이란 아직 실행되지 않은(정적인) 코드 덩어리를 말한다.

당연히 각종 언어로 작성된다. .C, .java, .py, .js etc...

 

이 프로그램을 실행하면 '프로세스'가 된다. 리눅스에서 htop 등으로 프로세스를 확인하여, 현재 서버에서 돌아가고 있는 프로세스의 상황을 파악해본 경험이 있을 것이다.

 

좀 더 자세히 설명하자면, 프로그램을 실행하면 OS는 프로그램을 실행하기 위한 시스템 자원을 프로세스에 할당합니다. 프로세스에 컴퓨터 리소스를 할당하는 것은 OS의 가장 중요한 역할 중 하나입니다. 프로세스는 각각 독립해있기 때문에 다른 프로세스에 접근할 수 없습니다.

 

 

  • (다른 프로세스에 접근할 수 없기 때문에 한 프로그램을 실행하기 위해 여러 프로세스를 할당할 수 없고, 이 문제를 해결하기 위해 실행 순서 내지는 경로를 의미하는 '스레드'가 필요하게 되는 것입니다.)
  • (사실 한 프로세스에서 다른 프로세스에 접근하여 정보를 가져올 수는 있긴 합니다만 별도 공유 메모리를 만들거나 IPC, LPC를 사용해야 하는 등의 절차가 있습니다.)

 

프로세스에 할당된 메모리는 Code, Data, Stack, Heap의 형식으로 할당해준다.

메모리 구조가 여기에서 나온 것이다. 메모리 구조에 대해서는 darrengwon.tistory.com/1007 참고

 

 

당연히 OS 커널을 통해 프로세스가 생겨나죠.

 

정제된 용어로 설명하자면 다음과 같다.

프로세스: 운영체제로부터 자원을 할당받은 작업의 단위.

작업관리자에서 현재 실행 중인 프로세스를 확인할 수 있다.

맥은 안 써봐서 모르겠고, ubuntu 환경에서는 확인 목적에 따라

ps -aux, ps -ef, top, htop 등이 사용된다. darrengwon.tistory.com/1070?category=860344

 

 

 

💻 프로세서(CPU), 멀티 프로세스을 가능케 하는 PCB(process control block)와 Context Switching

 

프로세스가 동작될 수 있도록 하는 하드웨어 = cpu

 

* 동작 : 프로그램의 자원들이 실행되기 위해 메모리에 올라오고, 실행되어야 할 코드의 메모리 주소를 cpu의 레지스터로 올리는 것

 

프로세서(cpu)는 한 순간에 하나의 프로세스만 실행할 수 있다. 

그러나 우리는 여러 프로세스가 동작하고 있는 것을 확인할 수 있다. 이를 멀티프로세싱이라고 한다.

 

이런 동작이 가능한 것은,

OS가 매우 짧은 시간에 로세스를 PCB(Process Control Block)에 담긴 정보를 참고하면서 교체(스위칭)하고 있기 때문에 여러 작업이 실행되고 있는 것처럼 느낄 뿐. 이를 멀티프로세싱이라고 부른다.

 

다시, 짧은 순간에 여러 프로세스를 교체해가면서 실행하기 위해서는 프로세스의 상태와 프로세스를 제어하기 위한 정보 모음(PCB)를 알아야 한다.

 

 

 

- PCB(Process Control Block)

 

프로세스를 컨트롤하기 위한 정보이다.

 

PID(process id), 프로세스 상태, 다음에 실행할 명령어의 주소, 이전에 작업하던 내용, CPU 스케쥴링 정보, 프로세스의 주소 공간 등이 담겨 있다. 이를 싸잡아서 Context라고 부른다.

 

각각의 내용들은 깊게 공부할 가치가 있지만, 아무래도 프로그래머로서 중요시해야할 부분은 프로세스 상태와 스케쥴링 정보이다.

 

 

- 프로세스 상태

 

OS가 각 프로세스들을 스위칭하면서 작업하면서 프로세스는 아래의 표와 같은 상태 변화를 겪게 된다.

프로세스가 실행되면 메모리에 적재되면서 Ready 상태.

스케쥴러에 의해 실행되면 Running.
Running 도중 프로그램이 I/O작업을 만나게 되면 Block된 상태가 된다.

 

https://eunhyejung.github.io/os/2018/07/08/operatingsystem-study06.html

 

💻 Context Switching

 

PCB의 정보를 통해서 프로세스를 교체하는 것을 알았다. 이런 프로세스 교체 과정을 Context Switching이라고 부른다.

좀 더 정확하게는, 기존 프로세스의 Context를 저장하고, 다음 프로세스를 실행할 수 있도록 Context를 교체하는 작업이다.

 

 

- Context가 뭐길래?

 

Context는 cpu가 프로세스를 실행하기 위한 프로세스에 대한 정보를 말한다. Context는 앞서 언급한 PCB에 저장된다.

 

 

- 언제 Context Switching이 일어나는가?(유식한 용어로 언제 기존 프로세스가 interrupt 되는가?)

 

당연히 다른 프로그램을 실행할 때 일어난다. 좀 더 자세하게는 아래와 같은 사항들이 있다.

 

1. I/O request (입출력 요청할 때)

2. time slice expired (CPU 사용시간이 만료 되었을 때)

3. fork a child (자식 프로세스를 만들 때)

4. wait for an interrupt (인터럽트 처리를 기다릴 때)

5. 이 외 등등...

 


- context switching은 자주하면 성능이 떨어진다. => 적절한 알고리즘을 사용하여 우선순위를 정한다.

 

여기서 문제는 Context Switching 중에는 해당 CPU는 아무런 일을 하지 못한다는 것이다. 따라서 컨텍스트 스위칭이 잦아지면 오히려 오버헤드가 발생해 효율(성능)이 떨어진다. 

 

* 참고로, Golang을 공부할 때 Go는 Go routine을 사용하여 Thread를 사용하는 C++이나 Java와 달리 Context Switching 비용 문제에서 이득을 본다고 살펴본 바가 있다.

 

여튼, Context Switching 과정을 쓸데없이 자주 반복하지 않도록 하고, 필요한 순간에 적절하게 하도록 하는 알고리즘이 필요하다는 뜻이다. 그리고 이 알고리즘을 사용하는 주체가 바로 운영체제 스케줄러이다.

 

 

- 그렇다면 무슨 알고리즘을 사용하여 프로세스 실행의 우선 순위가 결정되는가?

 

Node의 이벤트 루프에서도 사용되는 알고리즘인 라운드로빈 (Round-Robin)도 context switching을 위한 알고리즘 중 하나다.

 

크게 비선점 스케줄링과 선점 스케줄링으로 나뉘며 이 내부에 많은 알고리즘이 존재한다.

 

비선점 스케줄링 : 어떤 프로세스가 CPU를 점유하고 있다면 해당 프로세스의 작업이 완료될 때까지 다른 프로세스는 CPU를 사용할 수 없음.

 

선점 스케줄링 : 어떤 프로세스가 CPU를 점유하고 있을 때 우선순위가 높은 다른 프로세스가 점유를 빼앗아 CPU를 점유할 수 있음.

 

 

💻 스레드는 무엇이며 왜 필요하게 되었는가? => Context Switching 비용을 줄이기 위함

 

그런데 기술이 발전하면서 프로그램의 복잡도가 높아짐에 따라 한 프로그램을 실행하기 위해 하나의 프로세스만으론 부족하게 되었다.

 

앞서 프로세스에서 살펴보았듯 한 프로세스는 code, data, stack, heap를 가지고 있다.

프로세스가 전환되는 Context Switching이 발생하면 이 영역을 모두 내리고 실행하고자 하는 프로세스의 code, data, stack, heap를 다시 불러와야 한다.

 

이런 비효율을 줄여보고자 등장한 것이 Thread이다.

 

당연히 OS 커널을 통해 프로세스가 생겨나죠.

 

* 한 프로그램을 실행하는 프로세스를 여러 개 지정하는 방법은 불가능하다. OS는 안정성을 위해 프로세스마다 자신에게 할당된 메모리 내의 정보에만 접근할 수 있도록 했기 때문이다.

 

프로세스 내부에 실행하는 단위를 쪼개는 '스레드'를 이용하게 되면서 Context Switching 비용을 줄일 수 있게 되었다. 스레드는 한 프로세스 안에서 코드가 실행되는 수행 경로다. 같은 프로세스 내부에 존재하는 스레드는 메모리의 정보를 공유합니다. 

스레드는 프로세스의 코드에 정의된 절차에 따라 실행되는 특정한 수행 경로다.

 

한 프로세스 내에 여러 개의 스레드가 존재하면 멀티 스레드, 하나만 존재하면 싱글 스레드입니다.

node.js의 이벤트 루프는 싱글 스레드라고 했는데, 이는 노드 프로세스에 존재하는 실행 경로인 스레드가 하나 뿐이라는 의미입니다.

 

여기서 주의할 건, Thread라고 해서 Context Switching 비용이 아예 발생하지 않는다는 것은 아닙니다!

단지 code, data, stack, heap 전부가 아니라 stack만 교체하면 되기 때문에 Context Switching 비용이 낮을 뿐이죠.

 

 

💻 스레드의 구조

 

스레드가 어떻게 정보를 다른 스레드와 공유할 수 있는 지는, 공유한 메모리 구조에 해답이 있습니다. 프로세스가 할당 받은 메모리 중 Stack 형식으로 할당된 영역은 각 스레드가 각각 가지고 있으며 나머지 Code, Data, Heap 형식은 스레드가 공유합니다. 때문에 스레드는 코드, 데이터, 힙 메모리를 공유하게 되는 것이죠.

 

 

 

그림이 마음에 안들어서 직접 그려봤습니다.

 

 

 

여기서 우리는, 만약 하나의 스레드가 에러를 내게 된다면 같은 프로세스 내의 모든 스레드에도 에러를 내게 되며 결과적으로 프로세스가 종료된다는 사실을 유추할 수 있습니다.

 

 

💻 멀티 스레드

 

Stack 영역을 제외한 메모리를 공유하기 때문에 응답시간이 빨라지고 메모리도 아낄 수 있다는 장점이 있습니다.

반면 위에서 언급했듯, 한 스레드가 오류를 낸 경우 프로세스 전체가 종료되며, 자원을 공유하기 때문에 동기화 문제가 발생한다는 단점도 있습니다.

 

멀티 스레드를 사용한 경우, 순차적으로 실행될 것을 보장할 수 없습니다. 

 

구체적인 코드로 살펴보고 싶다면 멀티 스레딩을 통한 연산 처리는 아래 게시물을 참고해보자.

node.js에서 thread_workers 모듈을 통해 멀티 스레딩을 사용할 수 있다.

 

darrengwon.tistory.com/954?category=858366

 

Thread Pool을 활용해 멀티 쓰레딩로 고비용 연산 처리하기

libuv thread pool darrengwon.tistory.com/953 Row level Node : js의 동작 방식부터 libuv와 event loop까지 글을 시작함에 앞서, 본 포스트는 libuv가 C++으로만 작성되었다는 등의 잘못된 내용 등 일부를 수정..

darrengwon.tistory.com

 

 

💻 그러니까, 멀티 프로세스과 멀티 스레드는 다른거죠

 

멀티 프로세스는, 프로세스를 바꿔서 실행하는 것이고, Context Switching이 일어나면서 프로세스 전환이 일어나며, 자주 실행되면 성능이 좋지 않기 때문에 적절한 알고리즘을 통해 실행하는 것이 중요하다는 것을 살펴보았다.

 

멀티 스레드는 프로세스간 통신을 줄이고, Context Switching 비용을 줄이기 위하여 한 프로세스 내에서 여러 스레드를 두는 것을 말한다. 주의할 점은 Thread라고 해서 Context Switching 비용이 아예 발생하지 않는다는 것은 아니다. stack 영역에 대한 Context Switching 비용은 그대로이다.

 

 

 

 

참고한 글)

 

https://jeong-pro.tistory.com/93 

 

https://velog.io/@raejoonee/%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EC%99%80-%EC%8A%A4%EB%A0%88%EB%93%9C%EC%9D%98-%EC%B0%A8%EC%9D%B4

 

https://gmlwjd9405.github.io/2018/09/14/process-vs-thread.html

 

www.youtube.com/watch?v=hvcjeAZ2qCI&list=PLXvgR_grOs1BQCziQ_MpM877BdBxwbMzA&index=17&ab_channel=Ho-sungChoi

 

www.youtube.com/watch?v=DmZnOg5Ced8&ab_channel=%EC%9A%B0%EC%95%84%ED%95%9CTech

 


darren, dev blog
블로그 이미지 DarrenKwonDev 님의 블로그
VISITOR 오늘 / 전체