Node.js Worker 스레드 기본 예제

"A Raphael painting of Thor having a fencing match with black widow." from DALL-E 2

[개발환경]
운영체제 : Windows 10 Pro
Node.js 버전 : V12.14.0
CPU : AMD Ryzen 7 1700 8-core Processor
 
 
app.js
const path = require('path');
const envInfo = require('./env_info.json');
const {
    Worker
} = require('worker_threads');
 
let workerPath = path.join(__dirname, './worker.js');
let resultArr = new Array(envInfo.numThreads + 1);
 
if (envInfo.useThread) {
    for (let i = 0; i < envInfo.numThreads; i++) {
        let myWorker = new Worker(workerPath);
        myWorker.postMessage(envInfo.jobSize);
        //INFO: 스레드로부터 데이터를 받음
        myWorker.on('message', result => {
            console.log(`${myWorker.threadId} result : ${result}`);
        });
    }
} else {
    console.time('main');
    for (let i = 0; i < envInfo.numThreads; i++) {
        resultArr[i] = doSomething();
    }
    console.timeEnd('main');
 
    for (let i = 0; i < envInfo.numThreads; i++) {
        console.log(`result : ${resultArr[i]}`);
    }
}
 
function doSomething() {
    let data = 0;
    for (let i = 0; i < envInfo.jobSize; i++) {
        data += i;
    }
    return data;
}
 
 
worker.js
const {threadId, parentPort} = require('worker_threads');
 
/** @jobSize number */
parentPort.on('message', jobSize => {
    console.time(`${threadId} thread`);
    let result = doSomething(jobSize);
    console.timeEnd(`${threadId} thread`);
    //INFO: 메인스레드에게 데이터 전달
    parentPort.postMessage(result);
 
    //INFO: parentPort 이벤트를 종료시켜줘야 함
    parentPort.close();
});
 
/** @jobSize number */
function doSomething(jobSize) {
    let data = 0;
    for (let i = 0; i < jobSize; i++) {
        data += i;
    }
    return data;
}
 
 
env_info.json
{
    "jobSize": 1000000000,
    "numThreads": 16,
    "useThread": true
}
 
[결과]
 
3 thread: 1873.345ms
3 result : 499999999067109000
6 thread: 1891.574ms
6 result : 499999999067109000
7 thread: 1904.920ms
7 result : 499999999067109000
11 thread: 1898.478ms
11 result : 499999999067109000
10 thread: 1904.858ms
10 result : 499999999067109000
9 thread: 1911.417ms
9 result : 499999999067109000
13 thread: 1913.859ms
13 result : 499999999067109000
4 thread: 1924.483ms
4 result : 499999999067109000
2 thread: 1922.013ms
2 result : 499999999067109000
8 thread: 1920.018ms
8 result : 499999999067109000
14 thread: 1911.864ms
14 result : 499999999067109000
1 thread: 1923.043ms
1 result : 499999999067109000
5 thread: 1929.311ms
5 result : 499999999067109000
16 thread: 1927.331ms
15 thread: 1926.271ms
16 result : 499999999067109000
15 result : 499999999067109000
12 thread: 1934.948ms
12 result : 499999999067109000
 
대체적으로 모든 작업은 2초안에 종료되었다.
 
 
순간적으로 모든 코어의 CPU 사용률이 100%를 기록했다.
 
 
[싱글스레드만 사용할 경우]
 
main: 16955.328ms
result : 499999999067109000
result : 499999999067109000
result : 499999999067109000
result : 499999999067109000
result : 499999999067109000
result : 499999999067109000
result : 499999999067109000
result : 499999999067109000
result : 499999999067109000
result : 499999999067109000
result : 499999999067109000
result : 499999999067109000
result : 499999999067109000
result : 499999999067109000
result : 499999999067109000
result : 499999999067109000
 
모든 작업을 처리하는데 약 17초가 걸렸다. (16스레드 대비 약 8.5배 느림)
 
 
16번의 작업을 여러 개의 스레드가 돌아가면서 작업하고 있다. (일부 스레드에서 작업량이 많음)
 
전체 프로젝트 소스는 여기에서 받으면 됩니다.