あなたのコードをスピードアップ!


アプリケーションを高速化する方法の一つはキャッシュを実装することです.
キャッシュは、ユーザーの応答時間をスピードアップするだけでなく、それはまた、効率的にシステム上のリソースの使用量を削減します.

しかし、キャッシュは何ですか?


In simple terms, Caching means storing frequently demanded things closer to those asking for it


キャッシュについて非常に美しく描写される単純な類推を見てみましょう.
特定のトピックについての記事を書いて、コンテンツのライブラリから本にアクセスしたいとします.
今、図書館から図書館からいくつかの情報を見たいと思う度に図書館に行くことができますが、それは非常に高価な操作です.あなたの家から図書館まで旅行、本を捜して、内容を書き留めて、あなたの家に戻って、もう一度この全部のプロセスを繰り返してください.
しかし、あなたができることは、図書館からこれらの本を借りることができますし、あなたと一緒に家に持ち帰ることです.
だから今、あなたが本からいくつかのコンテンツをルックアップする必要があるたびに、彼らはあなたの家の腕の範囲内にある.
この類推では、多くの内容(帳簿)が保存されているが、頻繁にアクセスするハードドライブとしての行為のライブラリソートはかなり高価であろう.そして、あなたの家はキャッシュのように動作します、そこで、あなたは情報のために頻繁に見て、比較的安いものにアクセスする必要がある本だけを持っています.
Pythonには、関数と呼ばれる組み込み関数のモジュールがあります.この関数は、他の関数を引数として受け取り、他の関数を返します.
また、関数のモジュールはキャッシュのためのlruountキャッシュのようなより高い順序関数を含んでいます.
ここでは、Pythonで簡単にキャッシュを実装しようとしましょう!
下のコードを保存します.Pyファイルを実行してみてください.の出力を見てみましょう.
import requests

cache = dict()

def get_article_from_server(url):
    print("Fetching article from server...")
    response = requests.get(url)
    return response.text

def get_article(url):
    print("Getting article...")
    if url not in cache:
        cache[url] = get_article_from_server(url)

    return cache[url]

get_article("https://realpython.com/sorting-algorithms-python/")
get_article("https://realpython.com/sorting-algorithms-python/")
get_article("https://realpython.com/sorting-algorithms-python/")
get_article("https://realpython.com/sorting-algorithms-python/")
上記のコードを実行すると、以下の出力が得られます.

を参照してください.Fetching article from server. . .一度だけ印刷されて初めてですか.
これは一度記事をフェッチしたからです.関数GetHelp記事でレスポンスとして送信する前に作成したキャッシュに保存しています.
したがって、同じ記事へのその後の呼び出しのために、サーバー/インターネットからそれをフェッチする必要はありません.
しかし、我々はちょうどそれを使用する必要があるたびにゼロからキャッシュを構築することはできません.我々が上で実装したキャッシュは比較的単純でした、しかし、我々がより複雑なキャッシングメカニズムを必要とするならば、どうですか?ありがたいことにPythonはいくつかの組み込み機能/デコレータは、私たちはそれを行うに役立つ!
数の階乗を計算する問題を取りましょう.
以下は、階乗を計算する単純なコードがどのように見えるかです.
def factorial(n):
    return n * factorial(n-1) if n else 1
しかし、このコードの問題は、Nの各新しい値の値を再計算することです.
つまり、7の階乗を計算すれば、7 x 6 x 5 x 4 x 3 x 2 x 1で計算された出力として5040を得ることができるということです
しかし、私が5の階乗を計算するならば、それは5のx 4 x 3 x 2 x 1を再計算します.
これらの計算は、キャッシュに格納することができます再計算する必要がなく再計算されたコンピューティングリソースと時間を全体的なシステムを効率的に節約!
代わりにキャッシュを使用するコードを変更しましょう.
from functools import cache

@cache
def factorial(n):
    return n * factorial(n-1) if n else 1

我々がfactorial(10)と呼ぶならば、キャッシュが空であるので、機能は11の再帰的な呼び出しをします.しかし、この後にfactorial(5)を呼ぶならば、コードは全くどんな計算もしません、それはちょうどキャッシュの値を調べて、それを返します.
そして、我々がfactorial(12)と呼ぶならば、コードは10までの値がすでにキャッシュに格納された時から、11と12のために2つの再帰的な呼び出しをするだけです.
すごい!今、我々はどのように我々はキャッシュを作成することができますし、いくつかの高価な操作を行う関数に適用するように我々はコードをスピードアップし、それがより計算効率的にすることを知っている.

少し迂回して、図書館の例を再訪問しましょう。


あなたは、他の後にトピックを研究し続けた結果として、あなたが保つことができるより多くの書籍を家を買ってきた!
キャッシュに関して、ここで起こったことは、あなたのキャッシュが無期限に成長したということです.
キャッシュの目的は小さくて、ユーザーによって頻繁にアクセスされているいくつかのデータを格納するだけです、あなたのキャッシュがあなたのハードディスクと同じくらい大きくなることは、このキャッシュを維持するのにかなり高価であるので、それが目的であるということを負かします.
それで、我々が現在必要とするものは、それが関連性を失って、もう頻繁にアクセスされないキャッシュから内容/情報を取り除くメカニズムまたは方針です.つまり、私たちの家に保管されている本の一部を図書館に持ち帰るのを手伝ってくれる政策が必要です.これはキャッシュ回避ポリシーが入っているところです.

キャッシュ回避方針


あなたのキャッシュをクリアし、それが無期限に成長してからそれを維持しているサイズを維持するように定義されている多くのような戦略があります.それらの政策のいくつかを簡単に見てみましょう.

  • 先入れ先出し( FIFO )
    最初にキャッシュに追加されたエンティティは、最初に削除されます.つまり、最古のエントリを回避します.

  • ラストインファーストアウト
    キャッシュの最後または最新のエントリに追加されるエンティティは、最初に削除されます.つまり、最新のエントリを回避します.

  • 少なくとも最近使われる(LRU)-
    長い時間で使用されていないエントリはキャッシュから取得されます.

  • 最近使用される(MRU)
    最近使用されたエントリはキャッシュから取得されます.

  • 最も頻繁に使用される
    アクセスしないエントリは、キャッシュからあまり頻繁に取得されません.
  • Lruの作業を少し詳しく説明しましょう.
    LRU戦略を使用してキャッシュを実装すると、ユーザーが使用している方法でアイテムを整理します.
    キャッシュ内のエントリにアクセスするたびに、LRUアルゴリズムはキャッシュの最上位(最近使用される)にこのエントリを移動します.
    今、アルゴリズムは、キャッシュを見て、それは、下部にあるエントリは、古いユーザーが使用されていないことを知っているので、それは安全に新しいエントリのための方法をキャッシュから削除することができます.
    下の画像を見てください.

    ここで、ユーザが記事1をフェッチすると、キャッシュは最新の記事を格納してユーザに提供する.
    ユーザーが別の記事を要求するとき.

    キャッシュは、記事2を最も最近として割り当てて、記事1の下で記事1を押します.
    このように、LRU戦略はキャッシュのサイズが管理されることができるように、どのエントリーがキャッシュから追い出される必要があるかについて特定します.
    Fibonacci数を計算する例でLRU戦略を実行してみよう
    以下はFibonacci番号を計算する単純なコードはどのようなものです
    def fibonacci(n):
        if n < 2:
            return n
        return fibonacci(n-1) + fibonacci(n-2)
    
    これが再帰関数であるので、Nの大きい値のために、この機能は計算的に重くなるでしょう.
    LRU戦略でこの機能にキャッシュを実装しましょう.
    from functools import lru_cache
    
    @lru_cache(maxsize=16)
    def fibonacci(n):
        if n < 2:
            return n
        return fibonacci(n-1) + fibonacci(n-2)
    
    以前に見たものと同様に、我々はLruuキャッシュデコレータを使用して、LRUの立ち退き戦略でキャッシュを実装します.
    ここでmaxsizeパラメータはキャッシュが成長できる最大サイズを定義します.
    さて、この関数を呼び出してキャッシュ情報を取得すれば、このような出力が得られます.

    こちらです.
    ヒット-キャッシュから返された呼び出しの数
    misses -キャッシュに存在しなかったコール数を計算しなければならなかった
    maxsize -キャッシュの最大サイズ.maxsizeを16と定義したので、出力は同じです
    currsize -キャッシュの現在のサイズ.キャッシュがいっぱいです

    まとめる


    キャッシュは、システム上のコンピューティングリソースを減らすだけでなく、コードをより速く実行させます.
    あなたのコードでキャッシュを実装すると、迅速かつ最適な結果を与えることによって大幅にユーザーエクスペリエンスを向上させることができます.

    ソース


  • https://docs.python.org/3/library/functools.html
  • https://realpython.com/lru-cache-python/