2012-03-20 6 views
1

私は現在でビジネスレイヤで処理されている類似した要求の数を減らすためにしようとしている:キャッシュ要求(TPL?)

方法が遅いの実行
  • を受信要求をキャッシュ
    1. (すべての同様の要求のために1回)処理タスク各要求メソッドへ
    2. 戻る結果は注意することが

    物事を呼び出して、あるもの:

    • オリジナルのメソッド呼び出しがない現在非同期BeginMethod()/ ENDMETHOD(たIAsyncResult)
    • でリクエストが、それは私が使用しようとしている出力
    • を生成するのにかかる時間よりも早く到着しています可能であれば、私は現在このライブラリの詳細を学んでいるので、

    たとえば、以下を改善する

    byte[] RequestSlowOperation(string operationParameter) 
    { 
        Perform slow task here... 
    } 
    

    どのような考えですか?

    はフォローアップ:

    class SomeClass 
    { 
        private int _threadCount; 
    
        public SomeClass(int threadCount) 
        { 
         _threadCount = threadCount; 
         int parameter = 0; 
    
         var taskFactory = Task<int>.Factory; 
    
         for (int i = 0; i < threadCount; i++) 
         { 
          int i1 = i; 
    
          taskFactory 
           .StartNew(() => RequestSlowOperation(parameter)) 
           .ContinueWith(result => Console.WriteLine("Result {0} : {1}", result.Result, i1));             
         }    
        } 
    
        private int RequestSlowOperation(int parameter) 
        { 
         Lazy<int> result2; 
         var result = _cacheMap.GetOrAdd(parameter, new Lazy<int>(() => RequestSlowOperation2(parameter))).Value;    
         //_cacheMap.TryRemove(parameter, out result2); <<<<< Thought I could remove immediately, but this causes blobby behaviour 
    
         return result; 
        } 
    
        static ConcurrentDictionary<int, Lazy<int>> _cacheMap = new ConcurrentDictionary<int, Lazy<int>>(); 
        private int RequestSlowOperation2(int parameter) 
        { 
         Console.WriteLine("Evaluating"); 
         Thread.Sleep(100);    
         return parameter; 
        } 
    } 
    
  • 答えて

    1

    これを行うには、高速で安全かつ保守的な方法です:

    static var cacheMap = new ConcurrentDictionary<string, Lazy<byte[]>>(); 
    byte[] RequestSlowOperation(string operationParameter) 
    { 
        return cacheMap.GetOrAdd(operationParameter,() => new Lazy<byte[]>(() => RequestSlowOperation2(operationParameter))).Value; 
    } 
    
    byte[] RequestSlowOperation2(string operationParameter) 
    { 
        Perform slow task here... 
    } 
    

    これは、キーごとに最大で1回RequestSlowOperation2を実行します。辞書が保持するメモリは決して解放されないことに注意してください。

    ConcurrentDictionaryに渡されるユーザーデリゲートは、ロックされて実行されません。つまり、複数回実行される可能性があります。私のソリューションでは複数の遅延を作成できますが、そのうちの1つだけが公開され、実現されます。

    ロックについて:この解決策になりますが、作業項目が(わずかな)ロック操作よりもはるかに高価であるため問題ありません。

    +1

    なぜ 'Lazy 'を使っているのですか?私は 'GetOrAdd()'に渡されたデリゲートは、そのキーの値がすでに存在する場合には実行されないと思います。 – svick

    +1

    これはロックを回避するものではないことに注意してください。複雑さを隠すデータ構造(ConcurrentDictionary)を使用しているだけです。 –

    +0

    あなたの提案はかなり良いusrです。私はちょうど私のシナリオでこの辞書をきれいにする方法をチェックしています。ご意見をいただきありがとうございます。 – Westy

    1

    正直なところ、ここで技術としてTPLの使用は、本当に重要ではありません、これはただまっすぐ並行性の問題です。共有リソース(キャッシュされたデータ)へのアクセスを保護しようとしています。そのためには、がロックする方法はです。キャッシュエントリがまだ存在していない場合は、すべての着信スレッドがそのスレッドを生成できるようにすることができます。後続のリクエスタは、キャッシュされた値が格納されるとその恩恵を受けることができます。キャッシュ。

    おそらく、ロックなしでこれを達成しようとしている理由をさらに詳しく知ることができます。あなたがやろうとしていることがより詳細に分かれば、私は自分の答えを喜んで修正するでしょう。ここで

    +0

    ありがとうございました。私は以前の質問を更新して、 "ロックを避けてください"を削除しました。 – Westy

    関連する問題