본문 바로가기
개발정리 (nodeJS)

[nodeJS] Node.js에서 Worker Threads 사용하기

by 할리갈리0 2024. 11. 13.

Node.js는 싱글 스레드 기반의 이벤트 루프를 사용하여 비동기 작업을 효율적으로 처리합니다. 하지만 CPU 집약적인 작업, 예를 들어 복잡한 계산이나 데이터 분석 등을 처리할 때는 멀티스레딩이 필요할 수 있습니다. Node.js는 이러한 작업을 위해 Worker Threads를 제공합니다.

 

 

1. Worker Threads란

[정의와 개념]

  • Threads는 Node.js에서 멀티스레딩을 구현하기 위한 모듈
  • 기본적으로 Node.js는 싱글 스레드로 작동하지만, Worker Threads를 사용하면 CPU를 많이 사용하는 작업을 별도의 스레드에서 실행 가능
  • 메인 이벤트 루프가 차단되지 않으면서도 성능 향상 가능

[Worker Threads 사용 이유]

  1. CPU 집약적인 작업 처리: 비동기 작업은 이벤트 루프에서 잘 처리되지만, 복잡한 계산이나 데이터 처리 작업은 이벤트 루프를 차단 해결 가능
  2. 멀티코어 CPU 활용: Worker Threads를 사용하면 멀티코어 CPU를 효과적으로 활용할 수 있어 병렬 처리 가능

 

2. Worker Threads 설정 및 기본 사용법

Worker Threads는 worker_threads 모듈 사용.

npm i worker_threads

 

[메인 스레드에서 Worker를 생성하고, Worker와 메시지를 주고 받기]

  1. isMainThread: 코드가 메인 스레드에서 실행 중인지 여부 확인
  2. Worker: 새로운 Worker 스레드 생성
  3. parentPort: 메인 스레드와 Worker 스레드 간에 메시지를 주고받기 위한 인터페이스
// main.js
const { Worker, isMainThread, parentPort } = require('worker_threads');

if (isMainThread) {
  console.log('메인 스레드에서 실행 중입니다.');

  // Worker 생성
  const worker = new Worker(__filename);

  // Worker에서 메시지를 수신
  worker.on('message', message => {
    console.log('Worker로부터 메시지:', message);
  });

  // Worker로 메시지 전송
  worker.postMessage('안녕하세요, Worker!');
} else {
  // Worker 스레드에서 실행
  parentPort.on('message', message => {
    console.log('메인 스레드로부터 메시지:', message);
    parentPort.postMessage('메시지를 받았습니다!');
  });
}

 

3. Worker Threads로 CPU 집약적인 작업 처리하기

[피보나치 수열을 계산하는 CPU 집약적인 작업을 처리하기]

  1. 피보나치 계산: Worker 스레드에서 재귀적으로 피보나치 수열 계산
  2. 메인 스레드에서 Worker 실행: 메인 스레드에서는 Worker를 생성하고 결과를 비동기로 기다리기.
  3. Worker Threads를 사용하여 CPU 집약적인 작업을 메인 스레드와 분리하여 실행
// fibonacciWorker.js
const { parentPort } = require('worker_threads');

function fibonacci(n) {
  if (n <= 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
}

// Worker에서 작업 실행
parentPort.on('message', n => {
  const result = fibonacci(n);
  parentPort.postMessage(result);
});
// main.js
const { Worker } = require('worker_threads');

function runWorker(fibonacciNumber) {
  return new Promise((resolve, reject) => {
    const worker = new Worker('./fibonacciWorker.js');

    worker.on('message', result => resolve(result));
    worker.on('error', reject);
    worker.on('exit', code => {
      if (code !== 0) reject(new Error(`Worker가 종료되었습니다. 코드: ${code}`));
    });

    worker.postMessage(fibonacciNumber);
  });
}

runWorker(40)
  .then(result => console.log(`피보나치 결과: ${result}`))
  .catch(err => console.error(err));

 

4. 메시지 전달 및 데이터 공유

  • Worker Threads는 메인 스레드와 데이터를 주고받을 때 메시지 전달을 사용
  • Node.js는 데이터를 JSON 직렬화 방식으로 전달하므로, 복잡한 객체나 큰 데이터를 전달할 때는 성능에 영향을 줌

[데이터 공유 방법]

  • Node.js는 **SharedArrayBuffer**와 같은 기능을 제공하여 메모리 공유 가능
  • Worker와 메인 스레드 간의 데이터를 효율적으로 공유 가능
// sharedBuffer.js
const { Worker, isMainThread, workerData } = require('worker_threads');

if (isMainThread) {
  const buffer = new SharedArrayBuffer(1024); // 메모리를 공유할 수 있는 버퍼 생성
  const worker = new Worker(__filename, { workerData: buffer }); //  Worker를 생성할 때 데이터를 전달하는 방법

  // 메모리 공유 예제
  console.log('메인 스레드에서 작업 중...');
} else {
  const buffer = workerData;
  // Worker 스레드에서 공유 메모리를 사용
  console.log('Worker 스레드에서 작업 중...');
}

 

5. Worker Threads의 장점과 주의사항

장점

  1. 이벤트 루프 차단 방지: Worker Threads를 사용하면 메인 이벤트 루프가 차단되지 않아 비동기 작업이 원활하게 실행
  2. 멀티코어 활용: Node.js는 기본적으로 싱글 스레드이지만, Worker Threads를 사용하면 멀티코어를 효과적으로 사용 가능

주의사항

  1. 복잡성 증가: 멀티스레딩을 사용하면 코드의 복잡성 증가
  2. 메모리 사용량: 각 Worker는 별도의 메모리 공간을 사용하므로 메모리 사용량이 증가 가능
  3. 에러 관리: Worker에서 발생하는 에러를 적절히 처리 필요

 

 

Worker Threads는 Node.js에서 CPU 집약적인 작업을 효율적으로 처리할 수 있는 강력한 도구입니다. 이벤트 루프를 차단하지 않고 멀티스레딩을 구현함으로써 성능을 크게 향상시킬 수 있습니다. 하지만 멀티스레딩의 복잡성과 메모리 사용량 증가를 잘 관리해야 합니다.

반응형