재귀 없는 퀵정렬을 JS와 C++로 구현하면서 수행속도를 측정하고자 하였다.
C++은 정수형 타입이더라도 1바이트, 2바이트, 4바이트, 8바이트로 개발자가 선택하여 사용해야 하는 반면, JS는 정수형과 실수형 타입 모두 number로 사용되고 있다.
다만, JS의 경우 ArrayBuffer를 통해 원하는 바이트 크기의 버퍼를 생성할 수 있고, Int32Array() 함수로 해당 버퍼를 래핑하여 배열 원소의 크기를 4바이트로 사용할 수 있다.
[기본 배열 사용시]
- JS에서 1억개 할당 시 기본 배열은 최대 6.8GB의 메모리 공간을 차지하였다.
- 정렬 시 시간은 13.452초 소요되었다.
- 메모리 할당 시간은 36.656초 소요되었다.
[고정 크기 배열 사용시]
- JS에서 1억개 할당 시 고정 크기 배열은 400MB를 사용하였다. 정확히 1억개의 4바이트를 할당하였다.
- 정렬 시 시간은 12.507로 기본 배열보다 근소하게 빨랐다.
- 메모리 할당 시간은 2.344초가 소요되었다. 시간이 기본 배열의 6% 정도밖에 되지 않았다.
테스트에서, C++에서는 4바이트 크기인 int 형으로 배열을 만들어 사용하였고, JS에서는 Int32Array 배열을 만들어 사용하였다.
데이터 개수를 2천만, 4천만, 6천만, 8천만, 1억으로 증가하여 수행시간을 측정하였다.
시간 : 초 | C++ (메모리 할당) | C++ (퀵정렬) | JS (메모리 할당) | JS (퀵정렬) |
2000만 | 0.702 | 2.01 | 0.531 | 2.439 |
4000만 | 1.426 | 4.255 | 0.956 | 5.11 |
6000만 | 2.145 | 6.545 | 1.478 | 7.714 |
8000만 | 2.868 | 8.881 | 1.901 | 10.606 |
1억 | 3.58 | 11.284 | 2.416 | 13.483 |
특이하게도, 메모리 할당하는 시간은 JS가 더 적게 소요되었다.
퀵정렬의 경우 C++가 전체적으로 JS보다 약 20% 빠른 처리성능을 보여주었다.
이 결과를 보고, JS와 같은 인터프리트 언어라고 해서 반드시 C++보다 많이 느린 것은 아니라고 생각하게 되었다. 이 정도의 차이는 실제 사용시 크게 체감되지 않을 정도로 볼 수 있을 것 같다.
코드는 다음과 같다.
[JavaScript]
const USE_FIX_ARR = true;
/** INFO: 파라미터 만큼 배열을 생성하고 랜덤값 입력 */
function generateRandomArray(numData){
let arr;
if(USE_FIX_ARR){
let arrBuffer = new ArrayBuffer(4 * numData);
arr = new Int32Array(arrBuffer);
} else {
arr = new Array(numData).fill(0);
}
for(let i=0;i<numData;i++){
arr[i] = Math.round(Math.random() * numData);
}
return arr;
}
function quickSort(arr, start, end){
let stack = [];
let low = start, high = end;
let pivot, tmp;
let i, j;
stack.push(high);
stack.push(low);
while(stack.length !== 0){
low = stack.pop();
high = stack.pop();
let curLength = high - low + 1;
if(low >= high){
//INFO: 한개밖에 없으면 continue
continue;
}
if(curLength > 2) {
//INFO: 2개 이상인 경우
let tmpMid = Math.round((low+high) >> 1);
//INFO: low, mid, high 중 중간값을 정해야 함
pivot = arr[low] > arr[high] ? (arr[low] > arr[tmpMid] ? (arr[tmpMid] > arr[high] ? tmpMid : high) : low) : (arr[high] > arr[tmpMid] ? (arr[tmpMid] > arr[low] ? tmpMid : low) : high);
{//SWAP
tmp = arr[high];
arr[high] = arr[pivot];
arr[pivot] = tmp;
}
pivot = high;
} else {
//INFO: 2개 밖에 없는 경우
if(arr[low] > arr[high]){
//SWAP
tmp = arr[low];
arr[low] = arr[high];
arr[high] = tmp;
}
continue;
}
//INFO: 피봇
pivot = arr[high];
i = low - 1;
j = high;
while(true){
while(arr[++i] < pivot);
while(arr[--j] > pivot);
if(i >= j) break;
tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
tmp = arr[i];
arr[i] = arr[high];
arr[high] = tmp;
stack.push(high);
stack.push(i+1);
stack.push(i-1);
stack.push(low);
}
}
function main(){
let numData = 100000000;
let dataSizeGap = 5000000;
for(let j=0;j<1;j++){
for(let i=0;i<3;i++){
console.time('mem');
let arr = generateRandomArray(numData);
console.timeEnd('mem');
console.log('Start Quick Sort; data size : ' + numData);
console.time('quick_sort');
quickSort(arr, 0, numData - 1);
console.timeEnd('quick_sort');
//console.log(arr);
}
numData += dataSizeGap;
}
}
main();
[C++]
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#define N 100000000
#define R 100000
#define STKSIZE N
//unsigned int arr[N];
int* arr = nullptr;
int top = 0;
int* stack = nullptr;
//int stack[STKSIZE];
void init_stack() {
top = 0;
}
void push(int i) {
if (top < STKSIZE)
stack[top++] = i;
else {
printf("stack full\n");
exit(0);
return;
}
}
int pop() {
if (top != 0)
return stack[--top];
else
return 0;
}
int isStackEmpty() {
if (top != 0)
return 0;
else
return 1;
}
void quickSort() {
int pivot, tmp;
int i, j;
int low, high;
init_stack();
low = 0;
high = N - 1;
push(high);
push(low);
while (!isStackEmpty()) {
low = pop();
high = pop();
if (low >= high) {
continue;
}
int curLength = high - low + 1;
int pivot;
if (curLength > 2) {
int tmpMid = (low + high) / 2;
pivot = arr[low] > arr[high] ? (arr[low] > arr[tmpMid] ? (arr[tmpMid] > arr[high] ? tmpMid : high) : low) : (arr[high] > arr[tmpMid] ? (arr[tmpMid] > arr[low] ? tmpMid : low) : high);
{
tmp = arr[high];
arr[high] = arr[pivot];
arr[pivot] = tmp;
}
pivot = high;
}
else {
if (arr[low] > arr[high]) {
tmp = arr[low];
arr[low] = arr[high];
arr[high] = tmp;
}
continue;
}
//INFO: 데이터가 최소 두개
pivot = arr[high];
i = low - 1;
j = high;
while (1) {
while (arr[++i] < pivot);
while (arr[--j] > pivot);
if (i >= j)
break;
tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
tmp = arr[i];
arr[i] = arr[high];
arr[high] = tmp;
push(high);
push(i + 1);
push(i - 1);
push(low);
}
}
void main() {
srand(time(NULL));
stack = new int[STKSIZE];
clock_t start, end;
for (int i = 0; i < 3; i++) {
top = 0;
start = clock();
arr = new int[N];
for (int i = 0; i < N; i++) {
arr[i] = (rand() * (rand() + 1)) % N;
}
end = clock();
printf("mem time : %lf\n", (double)(end - start) / CLOCKS_PER_SEC);
start = clock();
quickSort();
end = clock();
printf("quicksort time : %lf\n", (double)(end - start) / CLOCKS_PER_SEC);
delete[] arr;
}
delete[] stack;
}
'컴퓨터 공학 > JavaScript' 카테고리의 다른 글
TypeScript 4.3 신기능 정리 (0) | 2022.01.13 |
---|---|
Node.js 객체 복사 방식에 따른 수행시간 간단 비교 (0) | 2022.01.12 |
Node.js에서 기본 정렬 / 합병정렬 / 퀵정렬 속도 비교 (0) | 2021.06.07 |
Node.js 이벤트 루프 정리 (0) | 2021.04.17 |
Node.js Worker 스레드 기본 예제 (0) | 2020.07.24 |