[JS] Map(), Set()의 이상한 성능테스트
안녕하세요! aloveu입니다. 프로젝트를 진행하다 보면 성능문제가 항상 따라옵니다.
대용량의 데이터를 핸들링한다던지, 다른 작업들이 많다던지 하다 보면 어느새 버벅거리는 화면을 보게 됩니다.
프로젝트의 성능을 높이는 방법중에는 많은 방법이 있지만 오늘은 대용량의 데이터를 Object가 아닌 다른 방법으로 처리하는 법을 알아보도록 하겠습니다.
우리가 코딩테스트를 하면서 알고리즘 문제를 풀 때 자주 보이는 Map, Set입니다.
Map
Map()은 자바스크립트의 Key-Value 페어로 이루어져 있습니다. 이 Key를 가지고 Value를 get, set 할 수 있고 Key 값들은 중복이 될 수 없습니다.
키값으로는 모두 사용이 가능합니다. Map에서는 키값으로 객체나 함수도 가능합니다.
그리고 키의 순서가 있습니다. object는 그게 없어서 가끔 리스팅할 때 순서가 뒤죽 박죽 되는 경우가 있죠.
사용법
const map = new Map();
map.set('name', 'John');
map.set(1, 'one');
map.set({}, 'object');
console.log(map.get('name')); // 'John'
console.log(map.get(1)); // 'one'
console.log(map.get({})); // 'object'
맵에는 set, get, has, delete, clear, size, keys, values 등의 메서드와 프로퍼티가 있습니다.
글자 그대로 맵에 set으로 값을 저장하고 get으로 값을 얻고, has로 키가 존재하는지 알 수 있습니다.
그리고 delete로 값을 삭제하고 clear로 맵의 모든 요소를 제거하기도 하고요, size로 요소의 개수를 반환합니다.
Set
Set은 중복된 값을 허용하지 않는 유일한 값들의 집합입니다. 그래서 키가 없는 값만 저장이 됩니다.
사용법
const set = new Set();
set.add(1);
set.add(2);
set.add(1); // 중복값이므로 무시됩니다.
console.log(set.size); // 2
console.log(set.has(1)); // true
그래서 배열에서 중복된 값을 제거 하고 싶을 때 쓰는 방법 중 하나입니다.
셋에는 add, delete, has, clear, size 등의 메서드와 프로퍼티가 있는데 이건 예상이 되니 설명은 생략하겠습니다.
성능 비교
실제 성능 차이를 비교하기 위해서 간단한 벤치마크 테스트를 진행해 보겠습니다.
Write
먼저 쓰기 성능을 테스트 해볼께요.
// 객체 vs Map 성능 비교
const objectTest = () => {
const obj = {};
for (let i = 0; i < 1000000; i++) {
obj[i] = i;
}
return obj;
};
const mapTest = () => {
const map = new Map();
for (let i = 0; i < 1000000; i++) {
map.set(i, i);
}
return map;
};
console.time('Object Test');
const objResult = objectTest();
console.timeEnd('Object Test');
console.time('Map Test');
const mapResult = mapTest();
console.timeEnd('Map Test');
// 배열 vs Set 성능 비교
const arrayTest = () => {
const arr = [];
for (let i = 0; i < 1000000; i++) {
arr.push(i);
}
return arr;
};
const setTest = () => {
const set = new Set();
for (let i = 0; i < 1000000; i++) {
set.add(i);
}
return set;
};
console.time('Array Test');
const arrResult = arrayTest();
console.timeEnd('Array Test');
console.time('Set Test');
const setResult = setTest();
console.timeEnd('Set Test');
이 코드는 단순히 각 객체, map, 배열, Set에 100만 건의 데이터를 삽입하고 시간을 측정하는 코드입니다.
크롬으로 테스트를 돌려 본 결과
예상외의 값이 나왔습니다. 예전에 제가 테스트했을 때는 Map이 Object보다 처리 속도가 빨랐거든요.
그래서 더 큰 수로 테스트를 해봤는데 더 큰 차이가 벌어졌습니다.
Read
갑자기 궁금증이 막 생겨요 ㅋㅋㅋ. 그럼 얼마나 자료를 빨리 읽는지도 테스트해 봐야겠습니다.
// 객체 vs Map 조회 성능 비교
const objectLookupTest = () => {
const obj = {};
for (let i = 0; i < 1000000; i++) {
obj[i] = i;
}
const keys = Object.keys(obj);
for (let i = 0; i < 1000000; i++) {
const randomIndex = Math.floor(Math.random() * 1000000);
obj[keys[randomIndex]];
}
};
const mapLookupTest = () => {
const map = new Map();
for (let i = 0; i < 1000000; i++) {
map.set(i, i);
}
const keys = [...map.keys()];
for (let i = 0; i < 1000000; i++) {
const randomIndex = Math.floor(Math.random() * 1000000);
map.get(keys[randomIndex]);
}
};
console.time('Object Read Test');
objectLookupTest();
console.timeEnd('Object Read Test');
console.time('Map Read Test');
mapLookupTest();
console.timeEnd('Map Read Test');
// 배열 vs Set 조회 성능 비교
const arrayLookupTest = () => {
const arr = [];
for (let i = 0; i < 1000000; i++) {
arr.push(i);
}
for (let i = 0; i < 1000000; i++) {
const randomIndex = Math.floor(Math.random() * 1000000);
arr[randomIndex];
}
};
const setLookupTest = () => {
const set = new Set();
for (let i = 0; i < 1000000; i++) {
set.add(i);
}
const values = [...set.values()];
for (let i = 0; i < 1000000; i++) {
const randomIndex = Math.floor(Math.random() * 1000000);
set.has(values[randomIndex]);
}
};
console.time('Array Read Test');
arrayLookupTest();
console.timeEnd('Array Read Test');
console.time('Set Read Test');
setLookupTest();
console.timeEnd('Set Read Test');
이렇게 코드를 작성하고 읽기 테스트를 진행해 봅니다.
이 코드는 100만 개의 요소를 객체, Map, 배열, Set에 각각 삽입한 후에 무작위로 선택한 인덱스에 대한 조회 작업을 100만 번 수행하도록 만들었습니다.
읽기 속도는 그래도 Map, Set이 빠를 줄 알았는데 아니네요.
Delete
Delete는 Map보다 Object가 빠르네요. ㅋㅋㅋㅋ
근데 배열보다는 Set이 삭제가 우수했습니다. 근데 이건 예상했죠?! ㅋㅋ
결론
이 포스팅을 쓰려고 했을 때는 Map, Set이 읽기, 쓰기 속도가 빠르니 프로젝트를 진행할 때 나중에 성능이슈로 삽질하지 말고 미리 적용하자!라는 주제를 가지고 글을 쓰기 시작했습니다.
그런데 웬걸... ㅋㅋㅋㅋㅋ Object와 Array 쓰세요.
곰곰이 이 결과가 나온 이유를 생각해 봤습니다.
요즘 브라우저 밴더사들이 전통적인 자바스크립트에 대한 최적화에 주력해 왔던 것도 있고 Map, Set 같은 비교적 최근 구조들은 아직 충분하게 최적화가 이루어지지 않을 걸 수 있습니다. 그래서 또 시간이 지나면 Map, Set이 빨라질 수 있겠지요.
또 하나 자바스크립트 엔진 차이일 수 있어요.
다른 브라우저에서는 조금 다를 수 있습니다.라고 했지만 요즘은 거의 V8엔진을 사용하고 있네요 =ㅁ=;
결론이 이상하게 나버렸지만 어쨌든 저에게도 많은 도움이 되는 포스팅이었습니다.
봐주셔서 감사합니다. ^___^
참고
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Map
'IT > 개발' 카테고리의 다른 글
[CSS] Cascade Layers 정리 (93) | 2024.05.13 |
---|---|
[JS] 반복문들의 성능 체크 (79) | 2024.05.09 |
[CSS] 버튼을 누를 때 폭죽 터지는 animation을 넣어보기 (136) | 2024.04.29 |
[NPM] Axios Error (38) | 2024.04.23 |
[Js, Vue] AbortController + onMounted + onUnMounted (100) | 2024.04.22 |