Node/노드 기능

worker_threads

webmaster 2022. 7. 24. 17:29
728x90

노드에서 멀티 스레드 방식으로 작업할 수 있음.

  •  isMainThread: 현재 코드가 메인 스레드에서 실행되는지, 워커 스레드에서 실행되는지 구분
  • 메인 스레드에서는 new Worker를 통해 현재 파일(__filename)을 워커 스레드에서 실행시킴
  • worker.postMessage로 부모에서 워커로 데이터를 보냄
  • parentPort.on(‘message’)로 부모로부터 데이터를 받고, postMessage로 데이터를 보냄
  •  new Worker 호출하는 수만큼 워커 스레드가 생성됨

여러개의 워커 스레드

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', (value) => {
            console.log('워커로부터', value);
        })
        worker.on('exit', () => {
            threads.delete(worker);
            if(threads.size === 0) {
                console.log('워커 끝~');
            }
        });
        worker.postMessage('ping'); //워커스레드 생성
    }
}else{ //워커 스레드
    const data = workerData;
    parentPort.postMessage(data.start + 100);
}
  • workerData를 통해 워커스레드의 데이터를 읽어올 수 있다.

싱글 스레드 (에라스토테네스의 체)

const min = 2;
const max = 10_000_000;
const primes = [];

function generatePrimes(start, range){ //에라스토테네스의 체
    let  isPrime = true;
    const end = start + range;
    for(let i = start; i < end; ++i){
        for(let j=min; j<Math.sqrt(end); ++j){
            if(i !== j && i % j === 0){
                isPrime = false;
                break;
            }
        }
        if(isPrime){
            primes.push(i);
        }
        isPrime = true;
    }
}

console.time('prime');
generatePrimes(min, max);
console.timeEnd('prime');
console.log(primes.length);
  • 에라스토테네스의 체 : min ~ max까지 소수를 찾는 프로그램
  • 해당 연산은 오래 걸리기 떄문에 실제 서비스를 하기 힘들다 -> 해결책: 워커 스레드

멀티 스레드

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

const min = 2;
let primes = [];

function findPrimes(start, range){ //에라스토테네스의 체
    let  isPrime = true;
    const end = start + range;
    for(let i = start; i < end; ++i){
        for(let j=min; j<Math.sqrt(end); ++j){
            if(i !== j && i % j === 0){
                isPrime = false;
                break;
            }
        }
        if(isPrime){
            primes.push(i);
        }
        isPrime = true;
    }
}

if(isMainThread){
    const max = 10_000_000;
    const threadCount = 8;
    const threads = new Set();
    const range = Math.ceil((max - min) / threadCount);
    let start = min;
    console.time('prime');
    for(let i = 0; i< threadCount - 1; ++i){
        const wStart = start;
        threads.add(new Worker(__filename, {workerData:{start:wStart,range}}));
        start += range;
    }
    threads.add(new Worker(__filename, {workerData:{start, range : range + ((max - min + 1) % threadCount)}}));
    for( let worker of threads){
        worker.on('error',(error) => {
            throw error;
        });

        worker.on('exit', ()=>{
           threads.delete(worker);
           if(threads.size === 0){
               console.timeEnd('prime');
               console.log(primes.length);
           }
        });
        worker.on('message', (msg) =>{
           primes = primes.concat(msg);
        });
    }
}else {
    findPrimes(workerData.start, workerData.range);
    parentPort.postMessage(primes);
}
  • worker 스레드의 일을 배분하고, 종합하는 것 모두 이를 사용하는 쪽에서 직접 작성해 주어야 한다(어렵다)
  • 시간이 단축된 것을 확인할 수 있다.
  • 워커 스레드의 개수를 줄인다고 해서, 꼭 정비례해서 시간이 줄어드는 것은 아니다( 스레드를 생성하는 시간, 코어 갯수 등 여러 변수들도 시간에 영향을 주기 때문에)
728x90

'Node > 노드 기능' 카테고리의 다른 글

파일 시스템 사용하기  (0) 2022.09.04
child_process  (0) 2022.07.24
crypto와 util  (0) 2022.07.24
Url과 querystring  (0) 2022.07.24
os와 path  (0) 2022.07.24