안녕하세요 오랜만에 글을 쓰게 되는데요
여기서는 궁금증을 다 풀어갈 예정입니다.
목적부터 말씀 드리면
A 함수
0.2초마다 A라는 배열을 채웁니다.
B 함수
0.2초마다 A라는 배열에 값이 차면 꺼내와서 테스트 플랫폼에 해당 내용으로 자동화를 요청합니다.
문제점
2개의 함수 모두 계속 loop을 돌면서 진행하게되는데 배열을 채우는 A함수는 지속적인 CPU I/O 가 발생하게 됩니다.
Node.js에서는 기본적으로는 멀티스레드가 안되기 때문에 저번 포스팅에서 Piscina를 사용하는 예제를 보여드렸었습니다.
그래서 그에 대한 기본 샘플 파일을 작성 합니다.
Worker
'use strict'
// 테스트 용
let memoryArray = [];
let worker ={
today_resource_filtering,
filtered_resource_request_automation
}
function today_resource_filtering(){
return new Promise(async(resolve,reject)=>{
try {
let i=0;
let closeCondition = 1000;
while(true && i < closeCondition){
console.warn(`today_resource_filtering : ${i}`);
i++;
// await wait(1000);
}
console.warn('Test Complete');
resolve(true);
} catch (error) {
reject(error);
}
})
}
function filtered_resource_request_automation(){
return new Promise(async(resolve,reject)=>{
try {
console.warn('Request Server Resource');
let i=10;
let closeCondition = 1000;
while(true && i < closeCondition){
console.warn(`resource_automation_request : ${i}`);
i++;
}
console.warn('Test Complete');
resolve(true);
} catch (error) {
reject(error);
}
})
}
// 테스트용 유틸
function wait(time){
return new Promise(async(resolve)=>{
setTimeout(()=>{
resolve(true);
},time)
})
}
module.exports = worker;
Using Piscina
const path = require('path');
const Piscina = require('piscina');
const piscina = new Piscina({
filename:path.resolve(__dirname,'filter_and_request.js')
});
(async function(){
const res = await Promise.all([
piscina.run({},{name:"today_resource_filtering"}),
piscina.run({},{name:"filtered_resource_request_automation"}),
]);
console.warn(res);
})();
Not Using Piscina
let worker = require('./filter_and_request.js');
(async function(){
const res = await Promise.all([
worker.filtered_resource_request_automation(),
worker.today_resource_filtering()
]);
console.warn(res);
})();
Using Piscina 결과부터 보겠습니다.
엥? 멀티스레드라고 되어있었는데 한 작업이 끝나야 다른작업이 시작됩니다.
기존의 worker의 내용을 바꿔보겠습니다.
function today_resource_filtering(){
return new Promise(async(resolve,reject)=>{
try {
let i=0;
let closeCondition = 1000000000;
while(true && i < closeCondition){
i++;
// await wait(1000);
}
console.warn('Test Complete');
resolve(i+'==today_resource_filtering');
} catch (error) {
reject(error);
}
})
}
closeCondition 값을 바꾸면서 반복을 하고
(async function(){
console.time('using_basic_js');
const res = await Promise.all([
piscina.run({},{name:"today_resource_filtering"}),
piscina.run({},{name:"filtered_resource_request_automation"}),
]);
console.warn(res);
console.timeEnd('using_basic_js');
})();
각각의 실행자에서 이렇게 테스트해보겠습니다.
100000부터 0을 하나씩 추가하면 (워커가 2개니까 *2 하시면 될 것 같습니다.)
1. 1000000 (20만) ( Piscina - 73ms vs Node.js (Single Thread ) 3ms )
오잉? 왜 피시나에서 더 걸리는거같죠?
2. 10000000 ( 2000 만 ) ( Piscina - 74ms vs Node.js (Single Thread ) 13ms )
천만 정도 루프시 특이점이 노드는 10 ms 증가 피시나는 7 정도 증가 했습니다.
3. 100000000 ( 20억 ) ( Piscina - 545 ms vs Node.js (Single Thread ) 950ms )
둘의 차이가점점 좁혀집니다.
4. 10000000000 (200억) ( Piscina - 9002 ms vs Node.js (Single Thread ) 17767ms )
100억번의 루프 -> 워커가 2개기 때문에 어찌보면 200억 인데
여기서부터 차이가 나기 시작합니다. ( Piscina의 진가가 발휘됩니다. )
5. 마지막으로 (2000억 번 순환 ++시 ) ( Piscina - 1m 33s vs Node.js (Single Thread ) 3m 05ss )
점점 늘어날수록 차이가 벌어집니다. 2000억 순환시 3배의 가량이 차이가 발생하게 됩니다.
-> 기존의 10만 100만정도는 piscina의 인스턴스를 생성하기 위한 기본 세팅값에서 들어가는 작업에 대한 시간으로 보입니다.
1차 정리
Piscina는 기본 세팅 시 70ms 정도가 소요 된다.
Promise의 2개의 워커를 사용시 루프시간에 따라 다르지만 3배까지도 차이가 발생
바로 다음 포스팅에서는 최대워커 수만큼 호출시 와 지금 은 함수를 return new Promise로 해서 Promise.all 로 받았지만
사실 진짜 원하는건 멀티스레드아니였나
A , B함수에서A가 계속 루프돌고 CPU 연산을 하면 B는 실행도 못하는게 실행되는게 아니였나? 라는 의문에 대한 해결을 위한 포스팅을 하겠습니다.