穏やかでキャッシュ


私は早めの最適化について友人と大きな会話をした.
つのことは別のものに導かれました、そして、我々はキャッシングとメモ化について話し始めました.
私たち一人一人は、その問題について全く違った見方をしていましたが、私たち双方が合意した一つのことは、パフォーマンスの重要性です.
彼は、私が素人の条件で私の考えを説明することができるかどうか尋ねました、そして、バーニー・スティンスンが言ったように、挑戦は受け入れられました!
だから私たちが始める前に、どのような回想について話しましょう.

何がmemoizationですか?
memoizationは、同じ出力のために保存結果の再計算を防ぐために主に使用される最適化技術です.
基本的に、私たちのソフトウェアがより速く走ることを意味します.

なぜ、我々は、メモ化を使うべきですか?
私たちはより良いパフォーマンスとより速い結果のために回想を使うべきです.
たとえば、クライアント側のJavaScriptコードを使用する場合は、メインスレッドをチョークすることができず、冗長なUIを持ちます.ツ)/(株)

十分な話!私にコードを見せてください!
あなたは正しい私は読書をする前にいくつかのアクションを見たいと思います.
簡単な機能「add」を持っているとしましょう追加は2つの数字を取り、それらの枝の値を返します
const add = (a, b) => {
  return a + b;
};
この関数では、私たちは、それが呼ばれるたびに+ Bを再評価します.
これは“高価な”計算ではありません.したがって、我々はそのような何かのためにメモ化を使用することはありません、しかし、我々がそうするならば、我々はそのような何かをすることができました.
const cachedAdd = memoizer(add);

cachedAdd(2,3); // 5 Not Cached
cachedAdd(2,3); // 5 Cached
cachedAdd(2,3); // 5 Cached
それはすべての良いとよく、どのようにHECKは"memoizer "の作品ですか?
単純な一般的な"memoizer "を作成できるかどうかを見てみましょうhigh-order 機能を再利用することができます.
/**
 * Cache function results for given params
 *
 * @param {function} func
 * @returns {function(): (*)}
 */
function memoizer(func) {
  const cache = {};
  return function() {
    const key = JSON.stringify(arguments);
    if (cache[key] !== undefined) {
      return cache[key];
    }
    const result = func(...arguments);
    cache[key] = result;
    return result;
  };
}
この機能を書くことについての多くの方法がありますが、この実装ステップを一歩進めましょう.
“memoizer”は関数を受け取り、引数オブジェクトを使い、キーを作成するためにstringifyします.
キーがあれば、キーはキャッシュオブジェクトで利用可能かどうかをチェックするそうした場合、キャッシュされた結果を返します.
そうでない場合は、値を計算し、キャッシュに保存し、それを返します.

Memoization exchanges time for space.


私はあなたが何を考えているか知っている

金を見せて
ランタイム結果を見ましょう.
以下を見るために、悪名高いFibonacciシーケンス機能を使用します.
Fibonacciシーケンスは一連の数値です.
0 , 1 , 1 , 2 , 3 , 5 , 8 , 13 , 21 , 34 ,…
次の番号は、その前に2つの数字を追加することによって見つかります
このような機能を実装できました.
const fibonacci = n => {
  if (n <= 1) return 1;
  return fibonacci(n - 1) + fibonacci(n - 2);
};

const getFibonacci = (limit = 1) => {
   const arr = [];
   for (let i = 0; i <= limit; i++) {
      arr.push(fibonacci(i));
   }
   return arr;
};
このような関数を呼び出すことができます.
getFibonacci(30); // will result [ 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 ...]
制限が30のとき、letはベンチマークテストを実行します
console.time("fibonacci");
for (let i = 0; i <= 100; i++) {
   getCachedFibonacci(30);
}
console.timeEnd("fibonacci");
初めて実行すると、193.097 msになります
問題は、我々が100回このコードを実行する場合、それが少しも良くならなくて、ちょうど最悪になるかもしれないということです.
たとえば、このコードは、合計18357.116 MMSで、100回、イットトーンです.
我々がよりよくすることができるかどうか見ましょう?
以前に書いたmemoization関数を使って、新しいキャッシュされたFibonacci関数を作成します.
const cachedFibonacci = memoizer(fibonacci);

const getCachedFibonacci = (limit = 1) => {
  const arr = [];
  for (let i = 0; i <= limit; i++) {
    arr.push(cachedFibonacci(i));
  }
  return arr;
};
console.time("cachedFibonacci");
for (let i = 0; i <= 100; i++) {
   getCachedFibonacci(30);
}
console.timeEnd("cachedFibonacci");
今回は、他の結果を得ます.
最初に我々はそれを実行すると、それは以前のように結果として解決するために193.509 msを取るが、2回目以降から、関数は平均0.027 msになった
100回の繰り返しに対して合計199.988 msまで.

👑 その結果は、各反復に対して7000 ~ times .
今、私はあなたが何を考えているか知っているすべての問題はフィボナッチ1です
私は十分に強調することはできません、回想は銀の弾丸ではない、それはすべてのシナリオに適していません.
一方、正しく使用するときに、アプリケーションのパフォーマンスを助けることができる別の強力なツールです.

私は自分のメモ機能を作成する必要がありますか?
もちろん、あなたはそれを行うことができます、しかし、あなたがオープンソース、よくテストされた、よく文書化されたメモ化機能の1つを使用したい場合には、ここで短いリストです
  • memoizee
  • memoized
  • lodash.memoize
  • あなたが問題に関する質問または考えを持っているならば、私は彼らを聞くのが好きです、そして、一方、穏やかにしてください👑 キャッシュオン.