[weekly] [nb] 프로세스와 스레드
프로세스와 스레드에 대해 설명해 주세요.
프로세스 vs 스레드
항목 | 프로세스(process) | 스레드(thread) |
---|---|---|
개념 | 실행 중인 프로그램 인스턴스 | 프로세스 내 작업 실행 단위 |
메모리 | 독립적인 주소 공간 가짐 | 같은 프로세스 내에서 메모리 공유 |
통신방식 | 프로레스 간 통신(Inter-Process Communication) 등 별도의 수단 필요 | 메모리 공유로 빠른 통신 공유 |
독립성 | 하나 죽어도 다른 프로세스에 영향 없음 | 하나 죽으면 프로세스 전체에 영향을 줄 수 있음 |
프로세스(process)
- 프로그램이 실행될 때 운영체제가 생성하는 독립된 실행 환경.
- 각 프로세스는 자기만의 메모리 공간을 가짐.
- node.js에서는 node app.js 실행 시 하나의 프로세스가 만들어짐.
스레드(thread)
- 프로세스 내에서 실행되는 작업 단위.
- 같은 프로세스 내 여러 스레드는 메모리를 공유하며 동시에 실행 가능.
- node.js는 단일 스레드 모델이지만, 내부적으로는 I/O 작업을 위해 libuv 스레드 풀을 사용함.
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