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
워커 끝
*/
외부 프로세스를 생성하고 실행할 수 있도록 해주는 내장 모듈
-> 이를 통해 운영 체제 명령어 실행, 다른 프로그램 실행, 병렬 작업 수행 등이 가능
//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());
});
파일 시스템에 접근하는 모듈
파일및 폴더 생성 삭제 존재여부 체크 등
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 관련 여러 함수들, 기능들이 있다...
파일 복사, 파일 존재여부 체크, 등등
필요하면 그때그때 공식문서, 서칭 등 해보기
일정한 크기로 모아두는 데이터
일정한 크기가 되면 한번에 통째로 처리
const buffer = Buffer.from('저를 버퍼로 바꿔보세요');
console.log(buffer);
console.log(buffer.length);
console.log(buffer.toString());
console.log(Buffer.alloc(5)); //5바이트 버퍼 생성
데이터의 흐름
일정한 크기로 나눠서 여러번에 걸쳐 처리
버퍼를 작게 만들어서 주기적으로 전달
스트리밍: 일정한 크기의 데이터를 지속적으로 전달
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); //**
노드는 기본적으로 background에서 4개의 thread까지 작업 가능
만약 본인의 코어가 그 이상이어서 본인컴퓨터의 코어만큼 작업시키고 싶으면
SET UV_THREADPOOL_SIZE=8(코어개수)을 터미널에 입력시키면 됨
커스텀 이벤트는 사용자가 정의한 이벤트
사용법
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지우기
예외: 처리하지 못한 에러
노드 스레드를 멈춤 -> 노드는 싱글스레드 -> 전체가 멈춰버림
해결법1:
try catch 문으로 예외 처리
해결법2:
콜백함수에서 err 처리하기
if(err) console.log(err);
해결법3:
process.on('uncaughtException',(err)=>{console.error('에러발생');});
-> 에러내용을 기록용, 모든 에러가 이 부분에 모여들어서 저장됨
프로세스 종료하기(강제종료)
taskkill /pid : 윈도우