2016-12-07 5 views
2

私はネットワーク経由でロードする必要があるデータを要求する複数のスレッドを持っています。 ネットワークトラフィックが少なくて応答が速いために、私はしばしば要求されるデータをキャッシュします。私はまた、キャッシュのデータサイズを制限したい。データサイズの制限でキャッシングを実装する方法は?

public class DataProvider 
{ 
    private ConcurrentDictionary<string, byte[]> dataCache; 
    private int dataCacheSize; 
    private int maxDataCacheSize; 
    private object dataCacheSizeLockObj = new object(); 

    public DataProvider(int maxCacheSize) 
    { 
     maxDataCacheSize = maxCacheSize; 
     dataCache = new ConcurrentDictionary<string,byte[]>(); 
    } 

    public byte[] GetData(string key) 
    { 
     byte[] retVal; 

     if (dataCache.ContainsKey(key)) 
     { 
      retVal = dataCache[key]; 
     } 
     else 
     { 
      retVal = ... // get data from somewhere else 

      if (dataCacheSize + retVal.Length <= maxDataCacheSize) 
      { 
       lock (dataCacheSizeLockObj) 
       { 
        dataCacheSize += retVal.Length; 
       } 
       dataCache[key] = retVal; 
      } 
     } 
     return retVal; 
    } 
} 

私の問題がある:私は確認してないか、dataCacheSizeは常に正しい値を持っていることを

私のクラスには、次のようになりますか? 2つのスレッドが同じキャッシュされていないデータを同時に要求すると、データはキャッシュに書き込まれますが、データは同じで、2番目のスレッドはキャッシュされたデータを同じデータで上書きするだけです。しかし、もしそれが上書きされたか、あるいはそのサイズを2回カウントすることを避けることができないのであれば、どうやって知っていますか?

また、2つのスレッドが許さよりも大きなデータキャッシュサイズが得られ、同時にデータを追加している...

は、複雑なロック機構を追加することなく、このタスクを達成するためのエレガントな方法があることが、起こるだろうか?

+4

キャッシングをロールするのではなく、System.Runtime.Caching.MemoryCacheを見てください。 https://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache(v=vs.110).aspx – Kevin

+0

いいえ、MemoryCacheがその仕事をしているようです。私はそのキャッシュ管理のオプションをチェックする必要があります。あなたはその質問に答えたいですか?私はコメントを受け入れることができません。 – Ben

+0

ありがとう – Kevin

答えて

1

代わりのキャッシングを「所有ロール」にしようとし、System.Runtime.Cachingを見てみましょう。 MemoryCache。上記のコメントを参照してください。

0

あなたはロックの内側dataCacheSizeを更新しているので、それが正しいのままであれば、あなたはちょうどここに確認することができます。

if (dataCacheSize + retVal.Length <= maxDataCacheSize) 
{ 
    lock (dataCacheSizeLockObj) 
    { 
     if (dataCacheSize + retVal.Length > maxDataCacheSize) 
     { 
      return retVal; 
     } 
     dataCacheSize += retVal.Length; 
    } 
    byte[] oldVal = dataCache.GetOrAdd(key, retVal); 
    if (oldVal != retVal) 
    { 
     // retVal wasn't actually added 
     lock (dataCacheSizeLockObj) 
     { 
      dataCacheSize -= retVal.Length; 
     } 
    } 
} 
+0

これは動作しません。 2つのスレッドが同じエントリを同時に追加したときに、retVal.LengthをdataCacheSizeに2回追加します。 – Ben

+0

この競合状態を解決するには、 'DataCache [key] = retVal'の代わりに' GetOrAdd'メソッドを使うことができます(私は答えを更新しました)。しかし、おそらく、System.Runtime.Caching.MemoryCacheを使用する方が良いでしょう。 –

関連する問題