今回のキャッシュとは、再帰計算等を行うときの無駄な計算をpythonに存在するデコレータを使用して簡単に高速化できる、と言ったようなもの。
キャッシュについて
計算や処理によって出された結果を一時的に保存することをキャッシュという。
そのキャッシュを利用し、同じ結果を2度目以降求める場合は処理をする必要なく、保存した内容をそのまま出す。
それによって同じ処理の複数回実行がなくなり、処理の手間が減ったり、場合によってはインターネットリソースの消費を減らしたり(本記事には出てこない)できる。
再帰処理をやってみる
今回はフィボナッチ数列の計算を例に説明する。
数式にすればなんか難しい感じがするが、プログラムでアルゴリズム的に書いてしまえばそれほど難しいものではないので問題ない。
早速だが、フィボナッチ数列をプログラムで書くと以下の様になる。
def fib(n):
print(n, end=' ') # 計算を可視化するためのprint
if n < 2:
return n
return fib(n - 1) + fib(n - 2)
これを実行してみよう。すると
fib(8)
#=>8 7 6 5 4 3 2 1 0 1 2 1 0 3 2 1 0 1 4 3 2 1 0 1 2 1 0 5 4 3 2 1 0 1 2 1 0 3 2 1 0 1 6 5 4 3 2 1 0 1 2 1 0 3 2 1 0 1 4 3 2 1 0 1 2 1 0
なんだかいろいろと同じような数字が大量に出力された。
fib(8)
の値を増やしてみると、もっと凄いことになる。
フィボナッチ数列をキャッシュで最適化
心配せずとも、全く難しいことはしない。
何故なら、筆者の頭でそんな難しいことは出来ないからだ。
以下の2行を、先程のプログラムの先頭に追加するだけ。
from functools import lru_cache
@lru_cache(maxsize = None)
これでメソッドを実行してみると......
fib(8)
#=>8 7 6 5 4 3 2 1 0
同じ数字が出力されていない......
@lru_cache(maxsize = None)
というデコレータをつけることによって、1度実行したメソッドと引数と戻り値をキャッシュし、2度目以降の同じ呼び出しはメソッドを呼び出さずキャッシュを使用する。
結果
使いどころを考える必要はあれど、結果を見ただけでそれなりの有用性がありそうだと言うことは分かるだろう。
付け足しではあるが、これによってキャッシュの有用性は理解出来たかと思う。
これ以外もキャッシュには様々な種類が存在し、現在多く使われている。
プロジェクトの規模や速度を求めるなら、やはりキャッシュを使うということは大なり小なり有利に働く(事が多い)。
これを機に、他のキャッシュについても調べてみると良いかも。
(補足)
個人的に解釈しやすいようにまとめたものの為、簡単な付け足し程度。
lru_cacheを使用したときの利点
fibを呼び出すときの引数と最終的な戻り値を内部でキャッシュ。
例えばfib(10)
が何度も呼ばれる環境だとしたら、fib(10)
を呼び出したときの戻り値をキャッシュしておく。
次にfib(10)
が呼ばれた時に、前回の戻り値をそのまま返すことで内部で走る何重もの再帰をパスし、関数の呼び出しもパスする。
その結果、同じ処理が多く走る再帰計算などで使用すると圧倒的な速さの処理が可能になる。