1

私は、キャッシュに値するほぼすべてのものを対象とした動的なエージング キャッシュとして機能するように設計された CFC を構築しました。LDAP クエリ、関数の結果、配列、オブジェクト、名前を付けます。計算に時間やリソースがかかり、複数回必要とされるもの。私はいくつかのことをできるようにしたいと思います:

  • アプリケーション間で CFC を共有する
  • キャッシュのスコープを定義する (サーバー / アプリケーション / セッション / 現在のリクエストのみ)
  • 同じリクエストで同時に異なるキャッシュ インスタンスを使用する
  • キャッシュ コンポーネントを使用して CFC から独立させる
  • 一般的に常識に従う(デカップリング、カプセル化、直交性、ロック)

もちろん、個別のタスクごとに異なるキャッシュ インスタンスを使用しますが、アプリケーション間で同じ CFC を使用できるようにしたいと考えています。キャッシュ自体は (それ以外は) Struct であり、キャッシュ インスタンスに対してプライベートです。スコープ自体が変更される可能性がある場合、キャッシュとロックを適切に実装するにはどうすればよいですか?

ロックには、現在、名前付きロック ( 'CacheRead''CacheWrite') を使用しています。これは安全ですが、奇妙に感じます。たとえば、セッションのみの操作でサーバー全体のロックが必要になるのはなぜですか? (はい、これアカデミックかもしれませんが、ともかく。)

アプリケーションレベルのキャッシュが必要な場合に参照として APPLICATION スコープを渡すことも間違っているようです。より良い方法はありますか?

4

2 に答える 2

2

わかりました-最初にあなたの質問を誤解したので、それ以上の混乱を引き起こさないように以前の回答を削除しました。

ロックに関する質問に答えるには:

名前付きロックは、常に同じ名前である必要はないため、問題ないはずです。アクセスしているキャッシュに応じて、動的に名前を付けることができます。プライベート構造体の要素にアクセスする必要がある場合は、名前付きロックにキーを名前として使用させるなどの操作を行うことができます。

このように、ロックが効果を発揮するのは、何かが同じキャッシュに名前でアクセスしようとした場合のみです。

于 2008-10-02T11:14:20.433 に答える
1

キャッシュ先の実際のスコープ構造を渡さないようにしたいというあなたの願望を理解していますが、選択肢は限られています。最初に頭に浮かぶのは、キャッシュを保存するスコープの名前(文字列)を渡して評価することです。その性質上、評価は非効率的であり、避ける必要があります。そうは言っても、私はそれがどのように達成されるのか興味がありました。私はあなたのコードを持っていないので、ここで単純な「ストレージ」抽象化CFC(テストしたいものとは無関係なので、キャッシュをスキップしました)を作成しました。

cache.cfc:

<cfcomponent>
    <cfset variables.cacheScope = "session" /><!--- default to session --->
    <cfset variables.cache = ""/>

    <cfscript>
    function init(scope){
        variables.cacheScope = arguments.scope;
        return this;
    }

    function cacheWrite(key, value){
        structInsert(evaluate(variables.cacheScope),arguments.key,arguments.value,true);
        return this;
    }

    function cacheRead(key){
        if (not structKeyExists(evaluate(variables.cacheScope), arguments.key)){
            return "";
        }else{
            variables.cache = evaluate(variables.cacheScope);
            return variables.cache[arguments.key];
        }
    }   
    </cfscript>
</cfcomponent>

そしてそれをテストするためのビュー:

<!--- clear out any existing session vars --->
<cfset structClear(session)/>
<!--- show empty session struct --->
<cfdump var="#session#" label="session vars">
<!--- create storage object --->
<cfset cacher = createObject("component", "cache").init("session")/>
<!--- store a value --->
<cfset cacher.cacheWrite("foo", "bar")/>
<!--- read stored value --->
<cfset rtn = cacher.cacheRead("foo")/>
<!--- show values --->
<cfdump var="#rtn#">
<cfdump var="#session#" label="session vars">

トピック外:jQueryのようなメソッド呼び出しを連鎖できるように、[これ]を返すセッター関数を作成するのが好きです(上記を参照)。ビューの一部は、次のように簡単に記述できます。

<cfset rtn = createObject("component", "cache")
    .init("session")
    .cacheWrite("foo", "bar")
    .cacheRead("foo")/>

これが可能であるのは興味深いことですが、Evaluateのオーバーヘッドコストのため、おそらく本番環境では使用しません。これは、キャッシュしたいスコープを渡すのに十分な理由だと思います。

それでも気になる場合は(そしておそらくそうですか?)、目的のスコープからの読み取りと書き込みを抽象化する別のCFCを作成し、それをストレージの場所としてキャッシュCFCに渡すことができます(ColdSpringに最適なタスク) 。 、そうすれば、キャッシュを別のスコープに移動することにした場合、初期化に「セッション」を渡すキャッシュCFCを使用して300ページをすべて編集する必要はなく、代わりに1つのCFCまたはColdSpring構成を編集できます。

リクエストスコープがあるのに、なぜシングルリクエストキャッシングが必要なのか完全にはわかりません。あなたが探しているのが現在のリクエストのために何かをキャッシュし、すぐにそれを死なせる方法であるなら、リクエストスコープはあなたが望むものかもしれません。キャッシングは通常、複数のリクエストにまたがる場合に価値があります。

于 2008-10-27T17:19:09.650 に答える