제목에서 어그로 끌었다.
성능 또 성능, 100만번 이상의 loop을 돌면서 몇 ms 단위로라도 실행시간을 단축시키고자 하는 사람들을 위해 javascript array 의 속내를 들여다보자.
이 글에서 알고자하는 것은 한줄요약하면
"(1) 빈 배열을 생성하고 원소를 그냥 우겨넣는 방식과 (2) 사이즈를 지정하여 초기화하고 값을 할당하는 방식에 속도차이가 있나?" 를 확인하는 것이다.
(1) 원소 추가
Array.prototype.push() 메소드를 사용하면된다.
✒️ tip) 자바스크립트는 기본적으로 타입이 없기 때문에 한 배열에 서로 다른 타입의 원소를 넣어도 문제가 되지 않는다.
(물론 타입스크립트로 명시적으로 자료형을 선언하면 트랜스파일링시 에러를 반환한다. 혹은 그 이전에 IDE 창에서)
(2) 배열 사이즈 명시적 초기화
new Array(array_length)
빈 배열을 선언하고, 랜덤숫자를 스트링으로 변환하여 200억회 추가한다.
console.time("test");
function test() {
const strArray : string[] = [];
for (let i : number = 1; i <= 2_000_000_000; i++) {
strArray.push(Math.random().toString());
}
strArray.forEach(console.log);
}
console.timeEnd("test");
// 0.063ms
배열 크기를 200억으로 미리 지정하고 1번째 index 부터 넣어보자.
console.time("test2");
function test2() {
const strArray : string[] = new Array(2_000_000_000);
for (let i : number = 1; i <= 2_000_000_000; i++) {
strArray[i] = Math.random().toString();
}
strArray.forEach(console.log)
}
console.timeEnd("test2");
// 0.062ms
이상한점을 눈치 챘나?
사실 사이즈가 200억이면 200억번째 인덱스는 존재하지 않는다.
근데 오류가나지 않는다.
js에서 배열은 같은 자료형을 미리 메모리에 잡아두는 것이 아닌
⭐ 배열이란 가면을 쓴 Hashmap 원소를 (key : index, value: value) 로 추가했을 뿐이기 때문이다.
0.001ms 밖에 차이나지 않는다. (200억 개 연산인데 이정도면 차이가 없다고 봐도 무방하다.)
node.js 가 아닌 web browser 에서도 테스트해봤다.
차이가 없다. 이번엔 심지어
push()
가 더 빨랐다.
일반적인 컴파일 언어 (C++의 vector.emplace_back() || push_back()
, Java와 Kotlin의 ArrayList.add()
)의 경우, 원소 추가 횟수가 많아져서 지정된 capacity를 넘어가면 O(N) 만큼의 복사가 일어나는 매커니즘을 가지고있어 속도가 느렸다.
따라서 배열의 크기를 미리 알 수 있다면 명시적으로 Capacity 를 지정해주는 방식의 초기화가 더 효율적이었다.
하지만 자바스크립트는 Capacity 를 지정하고 assign 한 방식이나 push 한 방식이나 차이가 없다.
그렇다. 배열이 아니라 배열의 탈을 쓴 HashMap 이라고 생각해도 좋다. // Javascript의 index 는 그냥 'key'에 불과하다.
가변배열에
push()
로 원소를 추가하는 방식이나 미리 크기를 지정하여 초기화Array()
한 방식이나 성능차이가 없다.
사이즈를 반드시 제한할 필요가 없다면push()
를 쓰자. 가독성이 더 좋다
js의 array는 object와 사실상 다를 바가 없다.
Performance를 높이기위해 미리 크기를 선언하고 assign 하는 방식은 다른 컴파일언어에서나 사용하자.
Javascript는 결국 해시맵으로 시작해서 해시맵으로 끝나는 언어다.