Javascript에서 컴퓨팅 시간을 줄이기 위해 메모이제이션 사용 시작
function fib(n) {
if (n === 0 || n === 1)
return n;
else
return fib(n - 1) + fib(n - 2);
}
위의 재귀 피보나치 함수의 주요 문제점은 비용이 많이 드는 함수라는 것입니다. 자신을 너무 많이 호출합니다. 제 형편없는 2015 Macbook air에서 fib(40)을 호출하는 데 약 30초가 걸렸고(자신을 102,334,155번 호출) fib(45)는 거의 5분(자신을 1,134,903,170번 호출 - 10억 번 호출)했습니다.
행운을 빌어 fib(100)을 호출합니다.
이렇게 값비싼 함수를 단축하기 위해 할 수 있는 일이 있을까요?
메모 입력
Memoization (기억과 운율)은 이전 결과를 캐시에 저장하는 CS의 기술이므로 동일한 인수로 함수가 다시 호출될 때 캐시에서 값을 반환하고 함수를 다시 실행합니다. 피보나치와 같은 값비싼 함수에 유용합니다.
피보나치에서 메모이제이션을 어떻게 사용합니까?
다음을 사용할 수 있습니다.
const fib = (function() {
const cache = {};
function f(n) {
let value;
if (n in cache) {
value = cache[n];
} else {
if (n === 0 || n === 1)
value = n;
else
value = f(n - 1) + f(n - 2);
cache[n] = value;
}
return value;
}
return f;
})();
(출처: here . 위의 모든 크레딧은 작성자에게 있습니다).
위의 함수를 시도하고 fib(40), fib(50) 및 심지어 fib(100)을 실행하십시오. 당신은 그 차이를 느낄 것입니다.
메모이제이션은 어떻게 작동합니까?
JS 객체( const cache = {};
)에 값을 저장하므로 동일한 값이 다시 호출되면 함수를 실행하는 대신 cache
에서 값을 가져옵니다.
우리가 fib(5)를 호출하고 싶다고 합시다. fib(5)가 처음 호출되면 캐시가 비어 있고 캐시에서 5를 찾을 수 없기 때문에(if (n in cache)
는 거짓임) 피보나치 논리(value = f(n - 1) + f(n - 2);
)를 실행한 다음 결과를 캐시(cache[n] = value;
에 저장합니다. ) ). 이제 n = 5
에 대한 캐시가 있습니다. {5: 5}
(btw, fib(5)의 값은 5입니다).
다음에 우리가 fib(5)를 다시 호출하면 캐시에서 ( {5: 5}
)을 찾습니다. fib(5)를 다시 실행하는 대신 단순히 캐시 조회에서 값을 반환합니다value = cache[n]; ... return value;
. 피보나치는 재귀적이기 때문에 fib(5)를 호출하면 자동으로 최대 5의 값으로 캐시를 채웁니다. fib(5)를 호출하면 fib(4), fib(3) 등에 대한 캐시가 생성됩니다.
또 다른 예는 방금 fib(49)를 호출했고 다음에 fib(50)을 호출하려고 한다고 가정합니다. fib(50)을 호출하기 전에 캐시 내부에는 다음과 같은 캐시 값이 있습니다.
{
0: 0,
1: 1,
2: 1,
3: 2,
...
48: 4807526976,
49: 7778742049
}
이미 0에서 49까지의 값이 있습니다! 우리가 해야 할 일은 value = f(n - 1) + f(n - 2);
를 호출하는 것입니다 - 일명 fib(49) + fib(48), 우리는 이미 캐시에 저장했습니다! 이것이 메모화 fib(50)이 메모화되지 않은 버전과 비교하여 거의 즉각적으로 결과를 반환하는 방법입니다.
달콤한! 눈에 보이는 모든 기능을 메모해 두겠습니다!
불행히도 모든 것을 메모할 수 있는 것은 아닙니다. 순수한 함수만 메모이제이션할 수 있습니다.
순수 함수가 되려면 다음을 수행해야 합니다.
다음을 사용할 수 있습니다.
const fib = (function() {
const cache = {};
function f(n) {
let value;
if (n in cache) {
value = cache[n];
} else {
if (n === 0 || n === 1)
value = n;
else
value = f(n - 1) + f(n - 2);
cache[n] = value;
}
return value;
}
return f;
})();
(출처: here . 위의 모든 크레딧은 작성자에게 있습니다).
위의 함수를 시도하고 fib(40), fib(50) 및 심지어 fib(100)을 실행하십시오. 당신은 그 차이를 느낄 것입니다.
메모이제이션은 어떻게 작동합니까?
JS 객체( const cache = {};
)에 값을 저장하므로 동일한 값이 다시 호출되면 함수를 실행하는 대신 cache
에서 값을 가져옵니다.
우리가 fib(5)를 호출하고 싶다고 합시다. fib(5)가 처음 호출되면 캐시가 비어 있고 캐시에서 5를 찾을 수 없기 때문에(if (n in cache)
는 거짓임) 피보나치 논리(value = f(n - 1) + f(n - 2);
)를 실행한 다음 결과를 캐시(cache[n] = value;
에 저장합니다. ) ). 이제 n = 5
에 대한 캐시가 있습니다. {5: 5}
(btw, fib(5)의 값은 5입니다).
다음에 우리가 fib(5)를 다시 호출하면 캐시에서 ( {5: 5}
)을 찾습니다. fib(5)를 다시 실행하는 대신 단순히 캐시 조회에서 값을 반환합니다value = cache[n]; ... return value;
. 피보나치는 재귀적이기 때문에 fib(5)를 호출하면 자동으로 최대 5의 값으로 캐시를 채웁니다. fib(5)를 호출하면 fib(4), fib(3) 등에 대한 캐시가 생성됩니다.
또 다른 예는 방금 fib(49)를 호출했고 다음에 fib(50)을 호출하려고 한다고 가정합니다. fib(50)을 호출하기 전에 캐시 내부에는 다음과 같은 캐시 값이 있습니다.
{
0: 0,
1: 1,
2: 1,
3: 2,
...
48: 4807526976,
49: 7778742049
}
이미 0에서 49까지의 값이 있습니다! 우리가 해야 할 일은 value = f(n - 1) + f(n - 2);
를 호출하는 것입니다 - 일명 fib(49) + fib(48), 우리는 이미 캐시에 저장했습니다! 이것이 메모화 fib(50)이 메모화되지 않은 버전과 비교하여 거의 즉각적으로 결과를 반환하는 방법입니다.
달콤한! 눈에 보이는 모든 기능을 메모해 두겠습니다!
불행히도 모든 것을 메모할 수 있는 것은 아닙니다. 순수한 함수만 메모이제이션할 수 있습니다.
순수 함수가 되려면 다음을 수행해야 합니다.
{
0: 0,
1: 1,
2: 1,
3: 2,
...
48: 4807526976,
49: 7778742049
}
불행히도 모든 것을 메모할 수 있는 것은 아닙니다. 순수한 함수만 메모이제이션할 수 있습니다.
순수 함수가 되려면 다음을 수행해야 합니다.
순수 함수는 이 문서의 범위를 벗어나지만 이 항목을 확인하십시오short article on pure function.
기타 참고 사항
메모이제이션은 굉장합니다. 하지만 남용하지 맙시다. 메모이제이션을 사용할 시기를 결정할 때 고려해야 할 몇 가지 사항:
좋네요. 그러나 실생활에서는 피보나치를 사용하지 않을 것입니다. 메모이제이션의 실제 사용 예가 있습니까?
예. VueJS은 메모이제이션을 활용합니다. cached(fn)
는 메모이제이션 래퍼입니다.
function cached (fn) {
var cache = Object.create(null);
return (function cachedFn (str) {
var hit = cache[str];
return hit || (cache[str] = fn(str))
})
}
그리고 그것은 여러 번 사용되고 있습니다:
const camelizeRE = /-(\w)/g
export const camelize = cached((str: string): string => {
return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : '')
})
export const capitalize = cached((str: string): string => {
return str.charAt(0).toUpperCase() + str.slice(1)
})
const hyphenateRE = /\B([A-Z])/g
export const hyphenate = cached((str: string): string => {
return str.replace(hyphenateRE, '-$1').toLowerCase()
})
이러한 기능을 찾을 수 있습니다here. (이 글을 쓰는 시점의 Vue 2.5.0. 향후 변경될 수 있지만 항상 이전 버전으로 돌아갈 수 있습니다.)
행복한 해킹!
자원
메모지에 대한 더 많은 정보:
function cached (fn) {
var cache = Object.create(null);
return (function cachedFn (str) {
var hit = cache[str];
return hit || (cache[str] = fn(str))
})
}
const camelizeRE = /-(\w)/g
export const camelize = cached((str: string): string => {
return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : '')
})
export const capitalize = cached((str: string): string => {
return str.charAt(0).toUpperCase() + str.slice(1)
})
const hyphenateRE = /\B([A-Z])/g
export const hyphenate = cached((str: string): string => {
return str.replace(hyphenateRE, '-$1').toLowerCase()
})
메모지에 대한 더 많은 정보:
순수 함수:
Reference
이 문제에 관하여(Javascript에서 컴퓨팅 시간을 줄이기 위해 메모이제이션 사용 시작), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/iggredible/javascript-start-using-memoization-to-reduce-computing-time-5cjk텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)