[Daily morning study] Node.js의 이벤트 루프와 비동기 I/O

#daily morning study

Image


Node.js의 이벤트 루프와 비동기 I/O

Node.js는 비동기적이고 이벤트 기반의 서버 사이드 JavaScript 환경입니다. 이러한 특징은 Node.js가 높은 성능을 발휘하게끔 도와줍니다. 이 학습 가이드에서는 Node.js의 핵심 개념 중 하나인 이벤트 루프와 비동기 I/O에 대해 살펴보겠습니다.

1. Node.js의 비동기 I/O

Node.js에서 비동기 I/O는 시스템 리소스를 효율적으로 관리하는 방법입니다. 전통적인 블로킹 I/O 모델은 모든 작업이 순차적으로 진행되므로, 하나의 I/O 작업이 완료될 때까지 다른 작업을 기다려야 합니다. 하지만 Node.js는 비동기 방식을 통해 상호작용을 최적화합니다.

1.1. 비동기 함수와 콜백

Node.js에서 비동기 작업을 수행하기 위해 주로 사용하는 방법은 콜백 함수입니다. 예를 들어, 파일을 읽는 비동기 함수를 호출할 수 있습니다.

const fs = require('fs');

fs.readFile('example.txt', 'utf8', (err, data) => {
    if (err) {
        console.error(err);
        return;
    }
    console.log(data);
});

console.log('파일을 읽는 중...');

위 예시에서 fs.readFile은 비동기적으로 파일을 읽으며, 파일 읽기가 완료되면 콜백 함수를 호출하게 됩니다. 이로 인해 프로그램은 파일을 읽는 작업이 완료되기까지 기다리지 않고, 콘솔에 “파일을 읽는 중…“을 출력하게 됩니다.

2. 이벤트 루프의 구조

이벤트 루프는 Node.js의 비동기 처리를 가능하게 해주는 핵심 메커니즘입니다. Node.js는 싱글 스레드에서 작동하며, 여러 작업을 동시에 처리할 수 있도록 이벤트 루프를 사용합니다.

2.1. 이벤트 루프의 단계

이벤트 루프는 여러 단계를 가진 반복 구조로, 각 단계에서는 큐에 대기 중인 콜백 함수를 실행합니다. 주요 단계는 다음과 같습니다.

  1. Timers: setTimeoutsetInterval을 통해 예약된 콜백을 실행합니다.
  2. IO callbacks: 거의 모든 비동기 I/O 작업의 콜백을 처리합니다.
  3. Poll: 새로운 I/O 이벤트를 체크합니다. 큐에 있는 콜백을 실행합니다.
  4. Check: setImmediate로 등록된 콜백을 실행합니다.
  5. Close callbacks: 종료 이벤트의 콜백을 실행합니다.

2.2. 이벤트 루프 흐름

이벤트 루프는 다음과 같은 흐름으로 작동합니다:

  1. 호출 스택이 비워지면 이벤트 루프는 타이머 큐를 확인합니다.
  2. 타이머 콜백을 실행한 후 I/O 콜백 큐를 처리합니다.
  3. 그 후 새로 등록된 이벤트가 있는지 확인하고, 실행할 수 있는 콜백을 찾아 실행합니다.
  4. 이 과정을 반복합니다.

3. 예제 코드

아래 예제에서는 비동기 I/O와 이벤트 루프의 순서를 이해하는 데 도움을 줄 수 있는 코드입니다.

const fs = require('fs');

console.log('시작');

setTimeout(() => {
    console.log('타이머 호출');
}, 0);

fs.readFile('example.txt', 'utf8', (err, data) => {
    if (err) {
        console.error(err);
        return;
    }
    console.log('파일 읽기 완료');
});

console.log('종료');

3.1. 출력 순서

위 코드의 출력 결과는 다음과 같습니다:

시작
종료
파일 읽기 완료
타이머 호출
  1. “시작”이 먼저 출력되고,
  2. 이어서 “종료”가 출력되며,
  3. 마지막으로 파일 읽기와 관련된 비동기 작업이 완료되면 “파일 읽기 완료”가 출력되고,
  4. 타이머 콜백이 마지막에 실행됩니다.

이러한 순서는 호출 스택과 이벤트 루프의 작동 방식 탓입니다.

4. 요약

Node.js의 비동기 I/O와 이벤트 루프는 고성능 서버 애플리케이션을 개발하는 데 필수적인 개념입니다. 비동기적으로 작업을 처리하고, 이벤트 루프를 통해 호출 스택을 관리함으로써, Node.js는 효율적으로 여러 클라이언트의 요청에 응답할 수 있습니다. 이러한 이해는 Node.js로 비동기 프로그래밍을 보다 깊이 있게 탐구하는 데 도움이 될 것입니다.