본문 바로가기
better code

[TIL] copy-on-write 방법론 - js에서 퍼포먼스 테스트

by marble25 2023. 4. 22.

함수형 프로그래밍 책을 읽다가 좋은 패턴 중 하나로 copy-on-write 원칙을 설명하는 것을 보았다.

js에서는 파라미터를 함수로 넘길 때 객체의 경우 레퍼런스를 넘기게 된다.

따라서 레퍼런스 값에 직접 access하다 보면 우리가 인지하지 못하는 변화가 있을 수 있다는 것이 논조이다.

예를 들어, 전역 변수를 parameter로 넘겨주고, 함수에서는 전역변수를 변경한다면, 해당 변수를 참조하는 또 다른 함수의 경우 예기치 못한 변화로 인한 버그가 발생할 수 있다는 것이다.

책에서 추천하고 있는 방향은 다음과 같다.

function f(arr) {
	const newArr = arr.slice();
	newArr[3] = "new";
	return newArr;
}

const arr = ["hello", "this", "is", "old"];
const newArr = f(arr);

위와 같이 구현하면 원본 객체에 변경 없이 함수의 리턴 값을 얻을 수 있다는 것이다.

하지만, 문득 이 방법을 언제나 사용할 수 있을지 궁금했다.

모던 프로그래밍 언어에서는 객체 복사를 어떻게 구현했을지 궁금했고, 퍼포먼스 타임은 얼마나 나올지 궁금했다.

그래서 위 책에서 제시한 언어대로, js에서 해당 메소드를 테스트해보았다.

퍼포먼스 테스트

const arraySize = 100000000;

const arrayToTest = Array(arraySize)
  .fill(0)
  .map((_, i) => i);

for(let i=0;i<5;i++) {
	console.time();
	const arr2 = arrayToTest.slice();
	console.timeEnd();
}

slice같은 경우에는 1 level의 copy를 제공하고, 1 level 밑의 element에 대해서는 reference만 가져온다.

약 10 million 정도의 배열을 생성해서 slice하는 부분의 시간을 측정했더니 약 80ms 정도로 나오는 것을 확인할 수 있다.

일반적인 경우에는 copy-on-write 방법론을 적용해서 진행해도 괜찮지만, 엄청 큰 크기의 배열을 다룰 때에는 한번 더 생각해 보는 것도 좋을 듯 하다.

'better code' 카테고리의 다른 글

리팩터링 - 마틴 파울러  (0) 2023.07.05
객체지향의 사실과 오해  (0) 2023.07.02
Clean Code (5/n)  (0) 2022.02.21
Clean Code (4/n)  (0) 2022.02.16
Clean Code (3/n)  (0) 2022.02.11