2

これはシナリオです:

  • スレッド A はフランス語ですべての本を求めます

  • スレッド B はアラビア語ですべての本を求めます

スレッド A がロック領域にある場合、スレッド B はスレッド A が終了するのをロック領域の外で待機します。

スレッド B がデータを取得できるコード内の「場所」は 1 つしかないためです。

次のようなキャッシュ内のキーに基づいてロックを作成したい:

if(Cache["BooksInFrench"] == null)
{
    lock("BooksInFrench")
    {
        if(Cache["BooksInFrench"] == null)
        {
        object d = GetFromDB();
        cache["BooksInFrench"] = d;
        }
}

BooksInArabic などについても同じです。このように、サイトへの接続が 200 あり、そのうちの 10 が BooksInFrench を要求した場合、残りの要求 (BooksInArabic、BooksInHebrew .......) を実行してデータを取得できます。彼らの要求はロック領域にないからです。

私の現在のコードは次のようになります: http://pastebin.com/LFhxgHDM

ダブルロックはあまり良くないと思います...他の解決策/改善点はありますか?

4

1 に答える 1

0

それはあなたの例の疑似コードにあるだけかもしれませんが、文字列よりもオブジェクトのロックが推奨されます(不変の共有文字列、正規バージョンなどの低レベルの最適化のため-文字列によるロックを参照してください。これは安全ですか?)。

単一の既知のlock:

// In your class
private static readonly object BooksInFrenchLock= new object();
private const string BookInFrenchCacheKey = "BooksInFrench";

// In your cache block
if(Cache[BookInFrenchCacheKey] == null)
{
    lock(BooksInFrenchLock)
    {
        if(Cache[BookInFrenchCacheKey] == null)
        {
            object d = GetFromDB();
            Cache[BookInFrenchCacheKey] = d;
        }
}

データベースから複数のオブジェクトをロックするConcurrentDictionaryには、ハッシュテーブルの代わりに ( pastebin コードに見られるように) を使用できます。これにより、ロックの「レベル」を 1 つ追加する必要がなくなります。で魔法が起こりBookLocks.GetOrAdd(bookLanguage, s => new object())ます。

// In your class
private static readonly ConcurrentDictionary<string, object> BookLocks =
    new ConcurrentDictionary<string, object>();

// In your cache block
string bookLanguage = formatAndCleanBookLanguageArgument();

if(Cache[bookLanguage] == null)
{
    object lockObject = BookLocks.GetOrAdd(bookLanguage, s => new object());

    lock(lockObject)
    {
        if(Cache[bookLanguage] == null)
        {
            object d = GetFromDB();
            Cache[bookLanguage] = d;
        }
}
于 2012-08-15T18:24:52.600 に答える