gyunam.blog

[weekly] [nb] 프로세스와 스레드

프로세스와 스레드에 대해 설명해 주세요.

프로세스 vs 스레드

항목 프로세스(process) 스레드(thread)
개념 실행 중인 프로그램 인스턴스 프로세스 내 작업 실행 단위
메모리 독립적인 주소 공간 가짐 같은 프로세스 내에서 메모리 공유
통신방식 프로레스 간 통신(Inter-Process Communication) 등 별도의 수단 필요 메모리 공유로 빠른 통신 공유
독립성 하나 죽어도 다른 프로세스에 영향 없음 하나 죽으면 프로세스 전체에 영향을 줄 수 있음

프로세스(process)

스레드(thread)

node.js 기준

구성 요소 설명
단일 프로세스 node 로 생성되는 단일 실행 instance, process.pid 로 확인 가능
메인 스레드 이벤트 루프 thread(js 코드 실행 담당)
스레드 풀 파일 읽기, DNS, 압축 등 비동기 작업을 처리하는 워커 thread(libuv, 기본 4개)

node.js 예제

프로세스

node.js 에서는 내장 process 객체로 프로세스의 정보를 확인할 수 있다.

const toMB = (bytes = 0) => (bytes / 1024 / 1024).toFixed(2) + 'MB';

console.log(`id: ${process.pid}`);
console.log(`resident set size: ${toMB(process.memoryUsage().rss)}`);
console.log(`heap total: ${toMB(process.memoryUsage().heapTotal)}`);
console.log(`heap used: ${toMB(process.memoryUsage().heapUsed)}`);
console.log(`uptime: ${process.uptime()}`);
id: 40326
resident set size: 38.42MB
heap total: 5.33MB
heap used: 4.41MB
uptime: 0.018853

실제로 테스트해보면 내가 작성한 서버의 설계와 동작 타이밍에 따라서 heap 사용량은 들쭉날쭉 변한다.

관련해서는 node.js 공식 문서 를 참고하면 된다.

힙(heap)

javascript에서 **heap(힙)**은 객체(Object), 배열(Array), 함수(Function) 과 같은 동적 메모리 할당 대상이 저장되는 공간이다.

그래서 참조형 자료형이 heap 에 저장된다. 반대로 원시형 자료형은 stack 에 저장된다.

node.js는 V8 엔진 위에서 작동하며, 이 엔진이 heap 영역을 자체 내장된 **GC(Garbage Collector)**를 통해 관리한다.

const stack = 10;
const heap = { data: 'hello,world.' };

메인 스레드(main thread)

항목 내용
정의 이벤트 루프가 동작하는 기본 실행 thread
역할 js 코드 실행, 콜백 관리, 이벤트 처리 등
갯수 단일
처리 방식 논블로킹 + 이벤트 루프(콜백 큐 → 실행)
예시 작업 대다수의 js 코드, promise, console.log 등
블로킹 영향 오래 걸리는 연산은 서버 전체 멈춤

node.js 는 I/O 에 대해서만 논블로킹

cpu 연산 은 여전히 블로킹으로 동작한다.

let total = 0;
for (let i = 0; i < 1e9; i++) {
  total += i;
  console.log('cpu 연산 중...');
}
console.log('cpu 연산 완료');
...
cpu 연산 중...
cpu 연산 완료

이벤트 루프(콜백 큐 → 실행)

카페에서 바리스타가 주문 종이에 온 것을 순차적으로 처리하는 것과 비슷하다.

항목 역할
이벤트 루프 바리스타
콜백 주문
콜백 큐 주문종이

스레드 풀(thread pool)

항목 내용
정의 libuv가 관리하는 백그라운드 작업자 thread 그룹
역할 비동기 I/O, 타이머, 파일 읽기 등 블로킹 작업을 오프로드 처리
갯수 기본 4개 (환경에 따라 설정 가능)
처리 방식 병렬(다중 thread)
예시 작업 fs.readFile, zlip.gzip, dns.lookup 등
블로킹 영향 개별 스레드에서 처리되므로 메인 스레드 차단 없음
import fs from 'fs';

fs.readFile('', 'utf8', (err, data) => {
  console.log('다른 thread');
});
console.log('메인 thread');
메인 thread
다른 thread