memoization

유연희·2022년 6월 30일
0

memoization

기존에 수행한 연산의 결과값을 저장해두고 동일한 입력이 들어오면 재활용하는 기법이다. Memoized된 내용을 재사용하여 렌더할 시, 가상 DOM에서 바뀐 부분을 확인하지 않아 성능이 향상된다.

리액트는 메모이제이션을 위한 세개의 api를 제공한다.

  1. 컴포넌트를 메모 - react memo
  2. 변수를 메모 - useMemo
  3. 함수를 메모 - useCallback

리액트 메모이제이션의 핵심은 바로 이전의 값만 메모이제이션 한다는 것이다.

memoization의 사용 비교

일반적인 재귀함수로 피보나치 수열 을 계산하는 함수를 구현하려고 한다면 다음과 같다.

피보나치 수열은 바로 앞 두 항의 합으로 이루어진 수열이다.
ex ) 0, 1, 1, 2, 3, 5, 8, 13, 21, ......


// 피보나치 수열을 재귀 함수로 계산하는 함수
let count = 0;
let fibonacci = function(number) {
    count ++;
    return number < 2 ? number : fibonacci(number - 1) + fibonacci(number - 2);
}

for(var i = 0; i <= 10; i++) {
    console.log(fibonacci(i)); // 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55
}
console.log("count : " + count) // count : 453

위 처럼 반복문으로 구현은 가능하지만 파라미터로 10이라는 비교적 작은 수를 주었는데도 fibonacci 함수는 453번이나 실행된다. 여기서 11번은 직접 호출한 것이지만, 나머지 442번은 이미 계산한 값들을 다시 계산하기 위해 호출한 것이다.


이때, 메모이제이션 패턴을 이용하면 반복되는 연산을 줄일 수 있다.
이미 계산한 내용들을 저장해두고, 다시 연산할 필요없이 저장된 데이터를 불러오는 방식이다.


let count = 0;
let fibonacci = function() {
    let memo = [0, 1];
    let fib = function(number) {
        count++;
        var result = memo[number];
        if(typeof result !== 'number') {
            result = fib(number - 1) + fib(number - 2);
            memo[number] = result;
        }
        return result;
    };
    return fib;
}();

for(var i = 0; i <= 10; i++) {
    console.log(fibonacci(i)); // 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55
}
console.log("count : " + count) // count : 29

우선함수 실행 횟수가 줄어든 것을 확인할 수 있다. 불필요한 연산을 줄였기 때문이다.


잘못된 사용

메모이제이션 한 함수 안에 state값이 있으면 state값 까지 memo되어 값이 바뀌지 않고 렌더링도 되지 않는다. 이런 경우는 useCallback을 잘못 사용한 경우이다.

// 잘못된 사용 
    const onClickCountState = useCallback(() => {
         setCountState(countState + 1);
    }, []);

// state 대신 prev 사용
    const onClickCountState = useCallback(() => {
         setCountState((prev)=> prev + 1);
    }, []);

결론
메모이제이션은 속도면에서 큰 이점이 있지만 속도를 위해 많은 메모리 사용량이 소비되기 때문에, 많은 RAM을 사용하는 함수를 처리해야 할 경우 영향을 준다고 한다.
아직까지 연산이 많이 필요한 코드를 작성해볼 일이 없어서 사용해보지 못했지만, 복잡한 연산이 있는 경우에 유용하게 쓰일 것 같다.

참고
https://frontsom.tistory.com/11
https://ko.reactjs.org/docs/hooks-faq.html#how-to-memoize-calculations

profile
developer

0개의 댓글