5

この質問は完全に App Engine 固有のものではありませんが、コンテキストを知るのに役立つ場合があります。App Engine には、ページをレンダリングし、さまざまなテーマやテーマ設定を介してスタイルを設定できる一種の「静的サイト ジェネレーター」があります。テーマは現在、App Engine ファイル システムに直接保存され、アプリケーションと共にアップロードされます。テーマは、いくつかのテンプレートと yaml 構成データで構成されます。

テーマの操作をカプセル化するために、Themeクラスがあります。theme = Theme('sunshine')たとえば、'sunshine' というテーマの構成データを読み込んで解析する Theme インスタンスを構築し、そのような呼び出しtheme.render_template('index.html')でファイルシステム上の正しいファイルを自動的に読み込んでレンダリングできるようにします。

問題は、新しいリクエストが来て a をインスタンス化するたびに、テーマの (yaml) 構成データを読み込み、特に解析するのThemeはコストがかかることです。したがって、データをプロセス/App Engine インスタンス内にキャッシュし、後で memcached 内にキャッシュしたいと考えています。

今まで、次のような非常に単純なキャッシュを使用してきました。

class Theme(object):
     _theme_variables_cache = {}

     def __init__(self, name):
         self.name = name

         if name not in Theme._theme_variables_cache:
             Theme._theme_variables[name] = self.load_theme_variables()

...

(複数のリクエストがコンストラクターに同時にヒットした場合、構成が複数回読み取られる可能性があることは承知しています。ただし、問題が発生するとは思いません。)

しかし、その種のキャッシングはすぐに見苦しくなります。構成ファイルから読みたいものがいくつかありますが、すべての異なるテーマの「名前」も異なる基本構成を指しているため、すべてのキャッシュは辞書です。

私が持っていた最後のアイデアはTheme._cached_func(func)、特定のテンプレートに対して関数の結果がまだキャッシュされていない場合にのみ func を実行するような関数を作成することでした (オブジェクトが別のテンプレートを表す場合、キャッシュされた値も異なる可能性があることに注意してください)。だから私はそれを次のように使うことができます: self.theme_variables = Theme._cached_func(self.load_theme_variables())、しかし、私はまだPythonにかなり慣れていないので、ここで明らかな何かが欠けていると感じています.

クラス全体をキャッシュ ロジックで混乱させることなく、このような状況で機能する明確でクリーンな Python キャッシュ パターンはありますか? テンプレートごとにキャッシュが異なる必要があるため、デコレータなどを介して関数の結果をメモすることはできないと思います。プロセスの実行中に基になる構成データが変更されないため、「古い」キャッシュの処理は必要ありません。

アップデート

私はそのようにそれをやった:

class ThemeConfig(object):
    __instances_cache = {}

    @classmethod
    def get_for(cls, theme_name):
        return cls.__instances_cache.setdefault(
            theme_name, ThemeConfig(theme_name))

    def __init__(self, theme_name):
        self.theme_name = theme_name
        self._load_assets_urls()  # those calls load yaml files
        self._load_variables()
...


class Theme(object):
    def __init__(self, theme_name):
        self.theme_name = theme_name
        self.config = ThemeConfig.get_for(theme_name)
...

ThemeConfigそのため、テーマのファイルシステムから読み取られたすべての構成要素が保存され、ファクトリ メソッドThemeConfig.get_forは同じテーマ名に対して同じ ThemeConfig インスタンスを常に渡します。私が持っている唯一のキャッシュ ロジックはファクトリ メソッドの 1 行であり、Themeオブジェクトは以前と同じように一時的で共有されていないため、好きなように使用したり悪用したりできます。

4

1 に答える 1

3

これを狙ってみます。基本的に、ファクトリ パターンを使用して、 Themeオブジェクトと特定の方法でのThemeインスタンスの作成との間の明確な境界を維持できます。

ファクトリ自体も、テーマ名と対応するテーマオブジェクトの間のマッピングを格納することにより、単純なキャッシュ戦略を維持できます。次の実装を使用します。

#the ThemeFactory class instantiates a Theme with a particular name if not present within it's cache
class ThemeFactory(object) :

     def __init__(self):
         self.__theme_variables_cache = {}

     def createTheme(self, theme_name):
         if not self.__theme_variables_cache.contains(name):
              theme = Theme(theme_name)
              self.__theme_variables_cache[name] = theme.load_theme_variables()
          return self.__theme_variables_cache[name]

Themeクラスの定義は非常にクリーンでシンプルになり、複雑なキャッシングは含まれません。

class Theme(object):

    def __init__(self, name):
        self.__theme_name = name

    def load_theme_variables(self):
        #contain the logic for loading theme variables from theme files

このアプローチには、コードの保守性と責任の明確な分離という利点があります (完全にはそうではありませんが、ファクトリ クラスは単純なキャッシュを維持します。理想的には、キャッシュ サービスまたはキャッシュを処理する別のクラスへの参照を単純に持つ必要があります。ポイント)。

Themeクラスは、テーマ変数の読み込みという最も優れた機能を果たします。ファクトリ パターンがあるため、 Themeインスタンスを作成するロジックからカプセル化されたクライアント コード ( Themeクラス インスタンスを使用するコード) を保持しています。アプリケーションが成長するにつれて、このファクトリを拡張して、さまざまなThemeオブジェクト ( Themeから派生したクラスを含む)の作成を制御できます。

これは、単純なキャッシング動作とインスタンス作成のカプセル化を実現する 1 つの方法にすぎないことに注意してください。

もう 1 つのポイント - テーマ変数の代わりに、テーマオブジェクトをキャッシュ内に格納できます。このようにして、最初の使用時にのみテンプレートからテーマ変数を読み取ることができます(遅延読み込み)。ただし、この場合、テーマ変数をThemeクラスのインスタンス変数として保存する必要があります。メソッドは次のload_theme_variables(self)ように記述する必要があります。

def load_theme_variables(self):
   #let the theme variables be stored in an instance variable __theme_variable
   if not self.__theme_variables is None:
       return self.__theme_variables
    #__read_theme_file is a private function that reads the theme files
   self__theme_variables = self.__read_theme_file(self.__theme_name)

これにより、ユースケースを達成する方法についてのアイデアが得られることを願っています。

于 2013-08-17T19:10:26.323 に答える