21

ジェネリックスレッドセーフのCacheメソッドを実装しようとしていますが、ロックをどのように実装すればよいのでしょうか。

次のようになります。

//private static readonly lockObject = new Object();

public T GetCache<T>(string key, Func<T> valueFactory...)
{

  // try to pull from cache here

  lock (lockObject) // I don't want to use static object lock here because then every time a lock is performed, all cached objects in my site have to wait, regarding of the cache key.
  {
    // cache was empty before we got the lock, check again inside the lock

    // cache is still empty, so retreive the value here

    // store the value in the cache here
  }

  // return the cached value here

}
4

3 に答える 3

7

プール間で共有されていないデータの場合

多くのプール(Webガーデン)がある場合、各プールは静的データを持つことができます。ConcurrentDictionary<TKey, TItem>そこで私は最近、内部の外観を使用しないある種の技術を実装しているため、より高速であると測定しました。そのため、非常に高速になっています。

ConcurrentDictionary<TKey, TItem>したがって、プール間で非共有データを使用することをお勧めします。

この場合、同じデータで同時にデータが変更されないように、自分でデータの同期に注意する必要があります。そこで、SlimLockまたはLockを使用できます。

共有リソースはプール間で変化します

これで、プール間で共有されるリソースがある場合、mutexを使用する必要があります。たとえば、多くのスレッドからファイルを保存しようとしたり、ファイルを開いて多くのスレッドからファイルを変更したりしようとする場合、その共通リソースを同期するにはミューテックスが必要です

したがって、共通リソースの場合、ミューテックスを使用します。
ミューテックスはキーを使用してロックし、そのキーのベースをロックできますが、同じリソースを変更することはできません。

public T GetCache<T>(string key, Func<T> valueFactory...) 
{
    // note here that I use the key as the name of the mutex
    // also here you need to check that the key have no invalid charater
    //   to used as mutex name.
    var mut = new Mutex(true, key);

    try
    {   
        // Wait until it is safe to enter.
        mut.WaitOne();

        // here you create your cache
    }
    finally
    {
        // Release the Mutex.
        mut.ReleaseMutex();
    }   
}

どんな錠前

ロック用に2つのケースがあります。

  1. 1つのケースは、すべてのプール、すべてのスレッドで共通のリソースを使用する場合です。共通のリソースは、ファイルまたはデータベース自体です。

共有リソースでは、mutexを使用する必要があります。

  1. 2番目のケースは、プールの内部にのみ表示される変数を使用する場合です。異なるプールはそのリソースを表示できません。たとえば、静的リスト<>、静的ディクショナリなどです。この静的変数、配列はプール内でのみアクセスでき、異なるプール間で同じではありません。

この2番目のケースでは、lock()が最も簡単で一般的な使用方法です。

ロックよりも速い

さて、静的辞書が長期間保持され、そこで読み取り/書き込みが多すぎる場合、プログラム全体が待機するのを回避するためのより高速なアプローチは、ReaderWriterLockSlim

ここから完全な例をとることができます:ReaderWriterLockSlim

ReaderWriterLockSlimを使用すると、ロックが不要な場合にロックを回避できます。また、読み取り時に静的な値をロックする必要はありません。書き込み時にのみロックを回避できます。したがって、静的な値については、それらをキャッシュとして使用することを提案できます。

asp.netのプールとは何ですか。

実行されるさまざまなプログラムが互いに分離しているが、ユーザーからの着信要求を処理するかのようにイメージングします。各プールには独自の世界があり、相互に通信していません。各プールには、初期化、静的な値、および寿命があります。プール間で共通のリソースを使用するには、データベース、ディスク上のファイル、サービスなど、他の3番目のプログラムが必要です。

したがって、共通のリソースと同期するために多くのプール(Webガーデン)がある場合は、ミューテックスが必要です。内部でそれらを同期するには、ロックを使用します。

IISアプリプール、ワーカープロセス、アプリドメイン
ASP.NET静的変数の有効期間

于 2012-05-23T07:39:29.163 に答える
3

LazyCachelibを見つけました。しかし、私はまだ本番環境でそれを試していません。

IAppCache cache = new CachingService();
ComplexObject cachedResults = cache.GetOrAdd("uniqueKey", 
    () => methodThatTakesTimeOrResources());
于 2017-02-03T21:53:51.043 に答える
0

.NETConcurrentDictionary<TKey, TItem>は、キーハッシュごとに個別のロックを作成することにより、これを内部的に実装します。これには、アイテムの追加と削除を処理する場合でも、関連する1つのハッシュのみをロックするという利点があります。

于 2013-12-22T14:25:17.983 に答える