본문 바로가기

Programming/Node.js

4. Node 기능 살펴보기 (4) - 노드 내장 모듈 9 [worker_threads] 2

node js logo image

 

 

 

 

앞선 아티클에서 워커 스레드를 사용하는 기본 유형에 대해서 살펴보았습니다. 일반적인 모듈이나 메서드의 활용 패턴이 아니기 때문에 예제 코드 이해가 다소 어려웠을 수 있습니다. 다시 한번 코드를 살펴보면서 확인해 보겠습니다. 

 

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

if (isMainThread) { // 부모일 경우
    const worker = new Worker(__filename);  
    worker.on('message', message => console.log('from worker', message));
    worker.on('exit', () => console.log('worker exit'));
    worker.postMessage('ping!');
} else {            // 워커일 경우
    parentPort.on('message', (value) => {
        console.log('from parent', value);
        parentPort.postMessage('pong!');
        parentPort.close();
    });
}

/* 출력
from parent ping!
from worker pong!
worker exit
*/

 

 

· 메인 스레드에서는 new Worker를 이용해 현재 파일(__filename)을 워커 스레드에서 실행시킵니다.

  → 단, else 블록 부분만 워커 스레드에서 실행됩니다.  

  → 메인 스레드에서는 워커 스레드를 생성한 다음, worker.postMessage( )를 이용해 워커 스레드에 데이터를 보냅니다.

 

· 워커 스레드에서는 이벤트 리스너인 parentPort.on('message')를 이용해 메인 스레드(부모)로부터 메시지를 받습니다.

   → parentPort.postMessage로 메인 스레드(부모)에게 메시지를 보냅니다. 

   → 부모 스레드는 worker.on('message')로 메시지를 받습니다. 

 

· 워커 스레드에서 on 메서드를 사용할 때는, 직접 워커 스레드를 종료해야 합니다(주의). 

   → parentPort.close( )를 실행하면 워커와 메인(부모)의 연결이 종료됩니다. 

   → 종료될 때는 worker.on('exit')가 실행됩니다.

 

 

 

 


 

 

 

이번에는 위의 예제에서 좀 더 응용하여, 여러 개의 워커 스레드에 데이터를 넘기는 예제를 만들어 보겠습니다. postMessage를 통한 데이터 전송과 약간 다른 형식입니다. 

 

참고로 Set( )은 아래 아티클을 다시 리뷰하시기 바랍니다. 

 

 

2. Javascript ES2015 (8) - Map/Set

ES2015에서 추가된 새로운 자료구조들 중, 자주 사용될만한 것은 Map, 그리고 Set입니다. 이미 JAVA에서도 Map과 Set을 다룬 적이 있기 때문에, 기본적인 개념은 각각의 아티클을 참고하는 것도 좋을 것

nozeroslope.tistory.com

 

 

 

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

if (isMainThread) {
    const threads = new Set();
    threads.add(new Worker(__filename, {
        workerData: { start: 1},
    }));
    threads.add(new Worker(__filename, {
        workerData: { start: 2},
    }));
    for (let worker of threads) {
        worker.on('message', message => console.log('from worker', message));
        worker.on('exit', () => {
            threads.delete(worker);
            if (threads.size === 0) {
                console.log('job done');
            }
        });
    }
} else {        // 워커일 경우
    const data = workerData;
    parentPort.postMessage(data.start + 100);
}

/* 출력
from worker 102
from worker 101
job done
*/

 

 

일단 위 예제에서처럼, new Worker를 호출할 때 두 번째 인수의 workerData 속성을 통해 데이터를 보낼 수 있습니다. 워커 스레드는 각각 workerData를 통해 각각 1과 2를 받는 상황이죠. 여기에 각각 메인(부모)으로부터 100을 받아서 더해 돌려줍니다. 돌려주는 순간 워커는 종료되어 worker.on('exit')가 실행되죠. 그리고 두 개의 스레드가 모두 끝나면 'job done'을 출력합니다.