worker_threads 모듈

seungjun.dev·2025년 7월 26일

Node.js

목록 보기
1/13

이미지 출처

이벤트 루프의 한계

JS의 메인 스레드는 한 번에 하나의 일만 처리한다.
이벤트 루프 모델은 시간이 걸리는 일들은 백그라운드에 위임하고 기다리지 않기 때문에 매우 효율적이다.

그러나 CPU 자체를 많이 사용해야 하는 무거운 계산 작업은 다른 곳에 위임할 수 없고, 메인 스레드가 직접 끝날 때까지 처리해야 한다.

이 작업이 실행되는 동안에는 다른 모든 작업(e.g. 사용자 클릭 반응, 화면 업데이트)이 멈추는 블로킹 현상이 발생한다. 이게 이벤트 루프의 한계다.

해결법

그래서 worker_threads를 사용한다.

  1. 별도의 작업자(스레드) 생성: 메인 스레드와는 완전히 독립적으로 동작하는 새로운 '워커 스레드'를 만든다.
  2. 무거운 작업 위임: CPU를 많이 쓰는 무거운 작업을 이 워커 스레드에게 통째로 맡긴다.
  3. 메인 스레드의 자유: 워커 스레드가 열심히 계산하는 동안, 메인 스레드는 그 작업에서 해방되어 원래 자신의 업무인 UI 반응이나 다른 가벼운 작업들을 멈춤 없이 계속 처리할 수 있다.

결론적으로 이벤트 루프를 대체하는 것은 아니다.
이벤트 루프의 약점인 CPU 집약적 작업으로 인한 메인 스레드 블로킹을 해결하여 병렬 처리를 할 수 있도록 보완해주는 강력한 도구다.

즉, 메인 스레드와 별도로 워커 스레드를 생성해 메인 스레드의 책임을 덜어주는 것과 같다.

사용법 예시

const { Worker, isMainThread, parentPort, workerData } = require('worker_threads');

if (isMainThread) {
    // 메인 스레드 로직: 워커를 생성하고 메시지를 보냅니다.
    const worker = new Worker(__filename, {
        workerData: "초기 데이터"
    });

    // 워커로부터 메시지 수신
    worker.on('message', (msg) => {
        console.log(`워커 스레드가 보낸 메시지: ${msg}`);
    });

    // 워커에게 메시지 전송
    worker.postMessage('나는 메인 스레드야!');

} else {
    // 워커 스레드 로직: 메인 스레드로부터 메시지를 받습니다.
    console.log(`메인 스레드가 보낸 초기 데이터: ${workerData}`);

    // 메인 스레드로부터 메시지 수신
    parentPort.on('message', (msg) => {
        console.log(`메인 스레드가 보낸 메시지: ${msg}`);
        // 메인 스레드에게 메시지 전송
        parentPort.postMessage('나는 워커 스레드야!');
        parentPort.close(); // 작업 완료 후 종료
    });
}
  • Worker 클래스: 메인 스레드에서 새로운 워커 스레드를 생성할 때 사용한다.
    생성자의 첫 번째 인자로 워커 스레드에서 실행할 파일 경로를 전달한다.

  • isMainThread: 현재 코드가 메인 스레드에서 실행되는지, 워커 스레드에서 실행되는지를 판별하는 boolean
    일반적으로 이 값을 기준으로 메인 스레드와 워커 스레드의 로직을 분기한다.

  • parentPort: 워커 스레드에서 메인 스레드와 통신하기 위해 사용하는 객체

  • postMessage(): 스레드 간에 메시지(데이터)를 전송하는 메서드
    메인 스레드에서는 worker 객체를 통해, 워커 스레드에서는 parentPort 객체를 통해 호출

  • workerData: 워커 스레드를 생성할 때 초기 데이터를 전달하기 위해 사용되는 옵션입니다.

스레드 간 통신은 이벤트 기반으로 이루어 진다.

  • 메인 스레드 → 워커 스레드: worker.postMessage()로 메시지를 보내고, 워커 스레드에서는 parentPort.on('message', ...)로 메시지를 받는다.

  • 워커 스레드 → 메인 스레드: parentPort.postMessage()로 메시지를 보내고, 메인 스레드에서는 worker.on('message', ...)로 메시지를 받는다.

profile
Frontend Engineer | Microsoft Student Ambassadors Alumni

0개의 댓글