본문 바로가기
Programming/Node.js

Node.js는 왜 싱글 스레드인가?

by p4cho 2024. 12. 21.
728x90

Node.js의 싱글 스레드 비동기 처리 방식에 대해 설명하겠습니다. 이 개념을 이해하기 위해서는 **이벤트 루프(Event Loop)**와 비동기 I/O에 대해 알아야 합니다.

 

🔥 1. Node.js는 왜 싱글 스레드인가?

싱글 스레드: Node.js는 **단일 스레드(메인 스레드)**로 동작합니다.

하지만 **비동기 작업(파일 입출력, 네트워크 요청, 타이머 등)**은 백그라운드 스레드 (Node.js 내부에 있는 libuv 스레드 풀)에서 처리합니다.

이를 통해 메인 스레드는 멈추지 않고 계속해서 다음 작업을 처리할 수 있습니다.

 

🔥 2. 이벤트 루프(Event Loop)란?

이벤트 루프싱글 스레드의 핵심 메커니즘으로, 대기 중인 작업을 관리하고, 작업이 완료되었을 때 콜백을 실행하는 구조입니다.

Node.js는 이벤트 루프를 통해 **비동기 작업(파일 입출력, 네트워크 요청 등)**이 완료되었을 때 콜백 함수를 실행합니다.

이벤트 루프는 아래의 6단계로 구성됩니다.

 

🔥 3. 이벤트 루프의 6단계 (단계별 이해)

1. Timers (타이머)

setTimeoutsetInterval의 콜백이 실행됩니다.

2. I/O Callbacks

대부분의 **비동기 I/O 작업(파일 입출력, 네트워크 요청 등)**이 완료되었을 때, 콜백이 실행됩니다.

3. Idle, Prepare

내부적으로 libuv의 준비 작업이 이루어지는 단계로, 보통 사용자 코드와 관련이 없습니다.

4. Poll (폴링)

새로운 I/O 이벤트가 있는지 확인합니다.

주요 작업 단계로, 파일 입출력 콜백은 주로 여기서 실행됩니다.

5. Check

setImmediate의 콜백이 실행됩니다.

6. Close Callbacks

소켓 연결과 같은 리소스를 닫는 작업이 실행됩니다.

 

🔥 4. 이벤트 루프가 요청을 처리하는 과정

 

이제 여러 요청이 연속으로 들어오는 상황에서 Node.js의 동작 방식을 단계별로 설명하겠습니다.

 

1️⃣ 요청 1, 요청 2, 요청 3이 들어옵니다.

2️⃣ Node.js의 메인 스레드는 각 요청에 대한 콜백을 이벤트 큐에 등록합니다.

3️⃣ **비동기 작업 (파일 입출력, 네트워크 요청 등)**은 백그라운드 스레드(pool)에서 실행됩니다.

4️⃣ 작업이 완료되면, 완료 신호가 이벤트 큐로 전달되고, 이벤트 루프가 대기 중인 콜백을 실행합니다.

5️⃣ 요청이 많아도, 메인 스레드는 절대 멈추지 않고 큐의 콜백을 순서대로 처리합니다.

 

🔥 5. 여러 요청이 동시에 처리되는지?

 

Node.js는 요청을 동시에 처리하지 않습니다.

대신, 비동기 I/O 작업이 동시에 실행될 수 있습니다.

 

자세한 설명

메인 스레드는 단일 스레드이므로 한 번에 하나의 자바스크립트 코드만 실행할 수 있습니다.

그러나, **백그라운드 스레드(libuv의 스레드 풀)**은 동시에 여러 비동기 작업을 실행할 수 있습니다.

예를 들어, 파일 읽기, API 호출, 데이터베이스 조회와 같은 비동기 작업은 동시에 실행됩니다.

메인 스레드는 대기 중인 콜백을 순차적으로 실행합니다.

 

🔥 6. 예시 코드로 이해하기

 

const fs = require('fs');

 

console.log('🚀 프로그램 시작');

 

// 비동기 파일 읽기 (이 작업은 libuv 스레드에서 수행됨)

fs.readFile('file1.txt', 'utf8', (err, data) => {

  if (err) throw err;

  console.log('📄 file1.txt 읽기 완료');

});

 

// 비동기 파일 읽기 (동시에 스레드에서 처리됨)

fs.readFile('file2.txt', 'utf8', (err, data) => {

  if (err) throw err;

  console.log('📄 file2.txt 읽기 완료');

});

 

console.log('🔄 메인 스레드의 다른 작업 수행');

 

🔥 7. 실행 순서 분석

1. console.log('🚀 프로그램 시작') 실행 (메인 스레드)

2. fs.readFile('file1.txt')백그라운드 스레드 풀에 위임

3. fs.readFile('file2.txt')백그라운드 스레드 풀에 위임

4. console.log('🔄 메인 스레드의 다른 작업 수행') 실행 (메인 스레드)

5. 백그라운드 스레드가 file1.txt와 file2.txt를 동시에 읽음

6. 작업이 완료되면 콜백 큐에 추가되며, 메인 스레드가 콜백을 실행합니다.

 

🔥 8. 동시성(Concurrency)과 병렬성(Parallelism)의 차이

Node.js는 동시성(concurrency)을 제공합니다.

한 번에 하나의 작업만 처리하지만, 작업을 멈추지 않고 다른 작업을 진행합니다.

메인 스레드는 쉬지 않고 돌아가며 대기 중인 작업을 실행합니다.

**병렬성(parallelism)**은 여러 스레드에서 작업이 동시에 실행되는 것을 의미합니다.

Node.js의 libuv 스레드 풀 덕분에 파일 입출력, 네트워크 요청과 같은 비동기 작업은 병렬로 처리됩니다.

 

🔥 9. 중요한 개념 요약

 

용어 의미

싱글 스레드 메인 스레드는 하나뿐입니다.

이벤트 루프 대기 중인 작업을 관리하고, 완료되면 콜백을 실행합니다.

비동기 작업 파일 I/O, 네트워크 요청 등은 백그라운드 스레드에서 처리됩니다.

백그라운드 스레드 libuv 스레드 풀에 의해 실행됩니다.

콜백 큐 작업 완료 후 실행할 콜백이 여기에 들어옵니다.

동시성 여러 작업이 대기 없이 진행되는 것 (병렬은 아님)

병렬성 여러 스레드에서 작업을 동시에 실행하는 것 (libuv 스레드 풀에서 발생)

 

🔥 10. 그림으로 이해하기 (단순화)

 

   [  Main Thread ]    이벤트 루프    콜백 실행

       

   [  백그라운드 스레드  ]  → 비동기 작업(파일 I/O, 네트워크 요청 등) 

 

🔥 11. 요약

Node.js는 싱글 스레드지만, libuv 스레드 풀 덕분에 비동기 I/O 작업이 병렬로 실행됩니다.

이벤트 루프는 콜백을 대기 중에 추가하고, 하나씩 실행합니다.

여러 요청이 들어오면 비동기 I/O는 동시에 진행되지만, 메인 스레드는 콜백을 순차적으로 처리합니다.

즉, Node.js는 비동기와 병렬성을 통해 높은 동시성 처리 능력을 갖추고 있습니다.

728x90