[Node.js]이벤트 루프(Evnet Loop)와 이벤트 기반(Event Driven)를 통한 Node.js 이해하기(프로세스/스레드/비동기)

[Node.js]이벤트 루프(Evnet Loop)와 이벤트 기반(Event Driven)를 통한 Node.js 이해하기(프로세스/스레드/비동기)

CS 상식 정리

먼저 간단한 CS 상식 정리하고 들어간다.

  • 프로세스

    논리적 단위로 물리적 단위 아님. 독립된 메모리 공간을 가지고 실행 중인 프로그램의 인스턴스(객체). 메모리 공간은 Code/Data/Stack/Heap으로 구분됨. ex) 웹 브라우저로 실행한 창 하나. 웹 브라우저 창을 2개 열면 프로세스 2개 실행 중인 것임 / 실행 중인 슈퍼 마리오 게임 하나. 슈퍼 마리오 게임 2개 실행하면 프로세스 2개 실행 중인 것임

  • 메모리 공간 별 간략 설명

    • 정적 세그먼트

      • Code : 말 그대로 작성한 코드 들어가는 부분.
      • Data : 전역변수, 정적변수, 배열, 구조체 등이 저장되는 부분. 프로세스 시작과 함께 할당. 프로세스 종료되면 소멸.
    • 동적 세그먼트

      • Stack : 임시 메모리 공간으로 함수 호출 시 생성되었다 함수 종료되면 다시 반환되는 부분.
      • Heap : 변수, 함수 저장, 호출 등의 작업이 발생하는 부분.
  • 스레드

    마찬가지로 논리적 단위로 물리적 단위 아님. 프로세스 내에서 실행되는 더 작은 단위. 한 프로세스 내에 여러 개의 스레드가 실행될 수 있는 개념. 같은 프로세스 내에 있는 스레드들은 프로세스의 메모리 공간을 공유(정확히는 스택(Stack) 메모리 빼고 공유. 스택 메모리를 각자 따로 가지고 있는 이유는 작업 자체는 스레드 개별적으로 알아서 진행되어야 하기 때문에 함수 호출 능력만 따로 부여해준 느낌). ex) 웹 브라우저 창 하나를 실행하면 프로세스가 하나 생긴 것이고, 이 프로세스 안에서는 렌더링 스레드, 네트워크 스레드, 자브스크립트 스레드 등이 각자 실행될 것임. / 슈퍼 마리오 게임 하나를 실행하면 프로세스가 하나 생긴 것이고, 이 프로세스 안에서는 오디오 스레드, 그래픽 스레드, 조작 스레드 등이 각자 실행될 것임.

Node js 용어 정리

Node js에서 사용되는 용어들을 간략하게 설명하고 넘어간다.

  • 이벤트 기반(Event Driven)

    이벤트 발생을 대비해서 미리 작업을 지정해두고 기다림. 이벤트가 발생하면 기다리고 있던 작업 수행.

  • 이벤트 루프(Event Loop)

    Node js가 실행되는 동안 끊임없이 일련의 과정을 반복함. 이런 끊임없는 반복 동작이 루프를 도는 것과 같다하여 루프라는 명칭 사용. 또한 이런 일련의 과정은 이벤트 처리를 위한 작업들이므로 이벤트 루프라고 명칭.

  • 싱글 스레드(Single Thread)

    Node js는 싱글 스레드로 동작한다고 표현한다. 이때 싱글 스레드는 말 그대로 하나의 스레드를 의미하고 Node js에서의 이 하나의 스레드는 메인 스레드라고도 불리고 동기적인 작업 처리나 이벤트 루프 관리 등 주요한 기능을 담당해 처리한다.(실제로는 메인 스레드인 싱글 스레드만으로 동작하지는 않음. 단순히 이벤트 루프가 대표적인 특징이기 때문에 이 하나의 스레드를 통해 돌아간다는 것을 강조(?)한다고 생각하면 됨)

즉, Node js는 하나의 싱글 스레드(이벤트 루프)가 반복적인 작업을 순서대로 루프처럼 무한히 반복하며 동작한다. 그럼 Node js에서 많이 들어본 비동기 처리는 어떻게 이뤄질까?

Node js 비동기 처리? Non-Blocking?

Node js는 비동기 처리를 통해 굉장히 빠르게 동작한다는 소리를 들어본 적이 있을 것이다. 나는 이때 싱글 스레드로 돌아가는데 어떻게 비동기 처리를 하는지 궁금했다. 싱글 스레드라면 작업을 처리할 수 있는 스레드 자체가 하나밖에 없기 때문에 하나의 스레드가 작업을 하고 있다면 다른 작업은 수행할 스레드가 없기 때문에 무조건 동기적으로 동작할 수 밖에 없지 않는가?

실제로는 Node js는 싱글 스레드가 아니다. Node js를 싱글 스레드라고 부르는 이유는 이벤트 처리 담당을 하고 있는 이벤트 루프라는 싱글 스레드가 대표적인 특징이기 때문에 싱글 스레드라고 부르는 것이다. 실제로는 Node js를 실행하면 하나의 프로세스가 생성되고, 해당 프로세스 안에 이벤트 루프라는 스레드 하나와 내부적으로 비동기같은 작업들을 처리해 줄 수 있는 스레드들 여러 개가 생긴다. 즉, 이벤트 처리는 이벤트 루프 하나로 싱글 스레드 작업이 이뤄지지만, 비동기 작업을 담당하는 여러 스레드들이 존재하고(Thread Pool) 이 스레드들이 이벤트 루프가 던져준 비동기 작업을 수행하고 결과값은 이벤트로 다시 반환하는 형태라고 생각하면 된다. 이벤트 루프는 우리같은 개발자들이 제어할 수 있지만 Thread Pool은 Node js의 libuv가 알아서 관리한다. 멀티 스레드 작업은 개발자가 직접 구현하기 굉장히 힘들다고 한다. 그래서 libuv에게 맡긴 형태다.

이런 동작 방식으로 인해 Node js는 Non-Blocking Event-Driven 방식이라고 부른다. 다시 요약하자면 다음과 같다. 이벤트 처리를 담당하는 이벤트 루프는 싱글 스레드로 동작하면서, 비동기적인 작업이 들어오면 수행이 완료되기 전까지 기다리지 않고 이벤트 루프 뒤에 존재하는 Thread Pool에 던져버린다. 이런 방식으로 막힘없이 계속해서 들어오는 입력을 처리한다. 그리고 이벤트 루프 뒤에 존재하는 Thread Pool에서 비동기 작업들을 알아서 각자 처리한 뒤 완료되면 이벤트 루프에게 이벤트 방식으로 알려줘서 완료되었다는 신호를 준다.

이벤트 루프 구조와 동기 비동기

위에서 설명한 이벤트 루프를 그림을 통해 이해해본다.

주요한 요소는 다음과 같다

  • 태스크 큐(Task Queue)

    (혹은 이벤트 큐(Event Queue)라고도 부름. 정확히는 태스크 큐가 이벤트 큐 하위 개념) 완료된 비동기 작업 콜백 대기 장소. 백그라운드 스레드들이 비동기 작업을 완료한 후 해당 작업의 콜백 함수를 태스크 큐에 넣어둔다.

  • 콜 스택(Call Stack)

    수행해야하는 함수들 대기 장소(To Do List 같은 역할). 실제로 Node js가 함수들을 실행하기 위해 확인하는 곳이라고 생각하면 된다. Node js 엔진은 콜 스택에 함수들이 대기하고 있으면 위에서부터 차례로(동기적으로) 해당 함수들을 실행한다. 콜 스택에 있던 함수들을 모두 처리해서 콜 스택이 텅텅 비게 되면 이벤트 루프가 이를 감지하고 이벤트 큐에서 대기 중인 콜백 함수를 콜 스택에 채워 넣는다.

  • 이벤트 루프(Event Loop)

    이벤트 루프는 비동기적인 작업 처리를 위해 여러 작업들의 처리 순서를 정리해주는 교통 경찰 역할을 많이 한다. 예를 들어 백그라운드 스레드에서 비동기 작업이 완료되었을 때 해당 작업의 콜백 함수를 이벤트 큐에 추가하는 행위도 이벤트 루프가 하고, 콜 스택에 비었을 때 이벤트 큐에서 대기 중인 콜백 함수를 콜 스택으로 이동시켜 실행하는 것도 이벤트 루프가 한다.

  • 메인 스레드(Main Thread)

    메인 스레드는 자바스크립트 엔진의 단일 스레드를 의미. 즉, 이벤트 루프를 포함하는 더 큰 개념이라고 생각하면됨.

Node js 비동기 작업

  1. 비동기적인 event 발생
  2. 이벤트 루프가 해당 event를 콜 스택에 추가
  3. 콜 스택에 있던 해당 event를 백그라운드 스레드가 수행 후 결과로 콜백 함수를 태스크 큐에 추가
  4. 이벤트 루프콜 스택이 비어있는 순간에 태스크 큐에 있던 콜백 함수를 콜 스택으로 옮김
  5. 콜 스택에 있던 콜백 함수를 메인 스레드가 수행하고 끝.

Node js 동기 작업

  1. 동기적인 event 발생
  2. 이벤트 루프가 해당 event를 콜 스택에 추가
  3. 콜 스택에 있던 해당 event 메인 스레드가 수행하고 끝.

즉, 동기 작업을 진행할 때는 메인 스레드가 해당 작업을 진행 중이므로, 메인 스레드가 담당하고 있던 이벤트 루프 동작은 멈추게 된다.

이 정도만 해도 전반적인 과정은 이해할 수 있다. 더 정확하게 들어가면 태스크 큐에도 우선순위에 따라 마이크로태스크 큐, 매크로태스크 큐로 나뉠 수 있는데 더 자세한 정보를 따로 찾자.

results matching ""

    No results matching ""