Nodejs Chap3.10~3.16)노드 기본기능

jade·2025년 2월 16일

Node.js

목록 보기
4/11
post-thumbnail

1. 내장모듈- worker_threads

1) 멀티스레딩 지원
기본적으로 Node.js는 단일 스레드에서 실행되지만, worker_threads를 사용하면 여러 개의 스레드를 실행 가능
CPU 연산이 많은 작업을 처리할 때 사용하면 성능 향상!

2) 메시지 기반 통신
메인 스레드와 워커 스레드는 postMessage()와 on('message')를 통해 데이터를 주고받으며 통신

3) 각 워커는 독립적인 실행 환경을 가짐
메모리를 공유하지 않고 실행됨 (단, SharedArrayBuffer를 사용하면 일부 메모리 공유 가능).

4) 개발의 번거로움, 어려움 존재
워커 스레드를 다 나눠줘야하고, 일을 하나하나 시키고 처리해야하는 번거로움, 어려움 존재

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('워커 끝');
            }
        });
    } 
} else { // 워커 스레드
    const data = workerData;
    parentPort.postMessage(data.start+100);
}
/*출력결과
워커로부터: 101
워커로부터: 102
워커 끝
*/

2. 내장모듈- child_process

외부 프로세스를 생성하고 실행할 수 있도록 해주는 내장 모듈
-> 이를 통해 운영 체제 명령어 실행, 다른 프로그램 실행, 병렬 작업 수행 등이 가능

//Node.js의 child_process 모듈을 사용하여
//외부 명령어(dir)를 실행하는 예제

const { exec } = require('child_process');
//exec()는 외부 명령어(프로그램)를 실행하고, 그 결과를 비동기적으로 반환하는 함수

var process = exec('dir');
//Windows에서 dir 명령어를 실행하여 현재 디렉토리의 파일 목록을 출력

process.stdout.on('data', function (data) {
    console.log(data.toString());
});

3. 파일 시스템

내장모듈- fs

파일 시스템에 접근하는 모듈
파일및 폴더 생성 삭제 존재여부 체크 등

fs.readFile('./chap3/readme.txt') //읽기
    .then((data) => {
        console.log(data.toString());
    })
    .catch((err) => {
        throw err;
    })
//파일 생성
fs.writeFile('./chap3/writefile.txt',"writenow")
    .then(( ) => {
        return fs.readFile('./chap3/writefile.txt');
    })
    //생성한 파일을 읽어서 내용 출력
    .then((data) => {
         console.log(data.toString())
    })
    .catch((err) => {
        throw err;
})

!비동기 파일 작업!

  • 파일을 읽는 건 "비동기"로 많이 진행됨, 동기로 진행하면 뒷사람이 파일작업을 하기까지 시간이 너무 많이 걸림
  • const fs=require('fs').promises : 비동기 작업으로 처리
  • 그러나! 비동기로 하면 코드 실행 순서를 예상할 수 없기 때문에 이를 잘 처리해주는 것이 중요함
  • 다음 코드를 읽어보면서 익혀보자
//chap3/fs_async.js
//주의해야할 점!
//비동기함수 -> 백그라운드로 넘어감
// -> 백그라운드에 넘어간 함수들이 동시 실행
// -> 누가 먼저 끝나는지 모른다는 단점 존재
//readFile을 비동기로 여러번 하면 어떤 파일을 먼저 읽을지 모름
//이 코드를 실행시켜보면, 1~4번이 무작위로 출력됨!
const fs = require('fs').promises;
fs.readFile('./chap3/readme.txt')
    .then((data) => {
        console.log("1번"+ data.toString());
    })
    .catch((err) => {
        throw err;
    })
fs.readFile('./chap3/readme.txt')
    .then((data) => {
        console.log("2번"+ data.toString());
    })
    .catch((err) => {
        throw err;
    })
fs.readFile('./chap3/readme.txt')
    .then((data) => {
        console.log("3번"+ data.toString());
    })
    .catch((err) => {
        throw err;
    })
fs.readFile('./chap3/readme.txt')
    .then((data) => {
        console.log("4번"+ data.toString());
    })
    .catch((err) => {
        throw err;
    })


//해결1: 비동기 + 순서예측 되게끔 + promise
fs.readFile('./chap3/readme.txt')
    .then((data) => {
        console.log("1번!");
        return fs.readFile('./chap3/readme.txt');
    })
    .then((data) => {
        console.log("2번!");
        return fs.readFile('./chap3/readme.txt');
    })
    .then((data) => {
        console.log("3번!");
        return fs.readFile('./chap3/readme.txt');
    })
    .catch((err)=>{
        throw err;
    })

//해결2: async로 해서 더 깔끔하게도 가능
async function main() {
    let data=await fs.readFile('./chap3/readme.txt')
    console.log("1번");
    data=await fs.readFile('./chap3/readme.txt')
    console.log("2번");
    data=await fs.readFile('./chap3/readme.txt')
    console.log("3번");
}
main();

이외에도 fs 관련 여러 함수들, 기능들이 있다...
파일 복사, 파일 존재여부 체크, 등등
필요하면 그때그때 공식문서, 서칭 등 해보기

2) 버퍼buffer

일정한 크기로 모아두는 데이터
일정한 크기가 되면 한번에 통째로 처리

const buffer = Buffer.from('저를 버퍼로 바꿔보세요');
console.log(buffer);
console.log(buffer.length);
console.log(buffer.toString());
console.log(Buffer.alloc(5)); //5바이트 버퍼 생성

3) 스트림stream

데이터의 흐름
일정한 크기로 나눠서 여러번에 걸쳐 처리
버퍼를 작게 만들어서 주기적으로 전달
스트리밍: 일정한 크기의 데이터를 지속적으로 전달

1. stream 읽기 쓰기 예제

//스트림 읽기
const fs = require('fs');
const readstream = fs.createReadStream('./chap3/readme2.txt');const data = [];
readstream.on('data', (chunk) => {
    data.push(chunk);
    console.log('data:', chunk, chunk.length);
});
readstream.on('end', () => {
    console.log('end', Buffer.concat(data).toString());
});
readstream.on('error', (err) => {
    throw err;
});
//스트림 쓰기
const writestream = fs.createWriteStream('./chap3/write2.txt');
writestream.on('finish', () => {
    console.log("쓰기 완료");
});
writestream.write('글쓰기\n');
writestream.write('한번 더 글쓰기\n');
writestream.end();

2. stream piping 예제

//16byte씩 읽고 그 16byte를 바로 writeme.txt에 쓰는 코드
const fs = require('fs');
const readstream = fs.createReadStream('./chap3/readme.txt',
    {highwatermark:16}
);
const writestream = fs.createWriteStream('./chap3/write3.txt');
readstream.pipe(writestream); //**

4. 스레드풀과 커스텀 이벤트

1) 스레드풀

노드는 기본적으로 background에서 4개의 thread까지 작업 가능
만약 본인의 코어가 그 이상이어서 본인컴퓨터의 코어만큼 작업시키고 싶으면
SET UV_THREADPOOL_SIZE=8(코어개수)을 터미널에 입력시키면 됨

2) 내장 모듈- 커스텀 이벤트

커스텀 이벤트는 사용자가 정의한 이벤트
사용법

  • EventEmitter 클래스를 사용하여 커스텀 이벤트를 정의하고 리스너들을 추가
  • 이벤트 발생 (emit) 시, 해당 이벤트에 등록된 리스너들이 호출됨
const eventemitter = require('events');
const myEvent = new eventemitter();

myEvent.addListener('event1', () => {
    console.log("1");
});
myEvent.on('event2', () => {
    console.log("2");
});
myEvent.once('event3', () => { //실행이 한번만 됨
    console.log("3");
});

myEvent.emit('event1');
myEvent.emit('event2');
myEvent.emit('event3');
myEvent.emit('event3');//이미 한번 실행을 해서 이번에는 실행안됨
myEvent.removeAllListeners('event1'); //event1지우기

5. 에러,예외 처리하기

예외: 처리하지 못한 에러
노드 스레드를 멈춤 -> 노드는 싱글스레드 -> 전체가 멈춰버림

해결법1:
try catch 문으로 예외 처리
해결법2:
콜백함수에서 err 처리하기
if(err) console.log(err);
해결법3:
process.on('uncaughtException',(err)=>{console.error('에러발생');});
-> 에러내용을 기록용, 모든 에러가 이 부분에 모여들어서 저장됨

프로세스 종료하기(강제종료)
taskkill /pid : 윈도우

0개의 댓글