2017-12-08 24 views
0

私は偉大な約AsyncLock libraryを読んでいますが、いくつか質問があります。リンクからasp.netキャッシュキーごとに適切な非同期ロック

例は、次のコード行があります。

private readonly AsyncLock _mutex = new AsyncLock(); 
public async Task DoStuffAsync() 
{ 
    using (await _mutex.LockAsync()) 
    { 
    await Task.Delay(TimeSpan.FromSeconds(1)); 
    } 
} 

は、私は私のASP.NETコントローラでこのコードを再利用しようとしたが、私はいくつかの疑問を持っています。上記

シナリオは、キャッシュキーが常に同じであるbacicロックをカバーしていますが、どのように私は、以下の例のように動的キャッシュを持っている、と私はArticleId1ロックにユーザーのロードArticleId2を望んでいないならばについて。 各キャッシュキーには自分自身のAsyncLock _mutexが必要ですか?

また、複数のユーザーがロックを共有するという事実のため、mutexを静的に変換する権限を持っていますか?

private static readonly AsyncLock _mutexIndex = new AsyncLock(); 
public async Task<IActionResult> Index(int articleId) 
{ 

    var key = CacheKeysFor.Article.ById(articleId); 
    ArticleModel cacheEntry; 
    cacheEntry = _cache.Get<ArticleModel>(key); 

    if (cacheEntry == null) 
    { 
     using (await _mutexIndex.LockAsync()) 
     { 
      if (cacheEntry == null) 
      { 
       cacheEntry = SomeDatabaseCall 
       _cache.Set(key, cacheEntry, TimeSpan.FromSeconds(60)); 
      } 

     } 
    } 

    return View(cacheEntry); 
} 
+0

「_cache」とは何ですか?それはMemoryCacheですか? – Evk

+0

@EvkこれはMemoryCacheですが、依存性注入によって切り替えると容易にRedisになる可能性があります。 – Robert

答えて

2

このルートを使用する場合は、各キーごとに個別のロックが必要です。あなたはConcurrentDictionaryと、たとえばそれを達成することができます:キーロックは時間をかけて蓄積されます

static ConcurrentDictionary<string, Lazy<AsyncLock>> _keyLocks = new ConcurrentDictionary<string, Lazy<AsyncLock>>(); 

public async Task<IActionResult> Index(int articleId) 
{  
    var key = CacheKeysFor.Article.ById(articleId); 
    ArticleModel cacheEntry; 
    cacheEntry = _cache.Get<ArticleModel>(key); 

    if (cacheEntry == null) 
    { 
     var keyLock = _keyLocks.GetOrAdd(key, _ => new Lazy<AsyncLock>(() => new AsyncLock())).Value; 
     using (await keyLock.LockAsync()) 
     { 
      if (cacheEntry == null) 
      { 
       cacheEntry = SomeDatabaseCall 
       _cache.Set(key, cacheEntry, TimeSpan.FromSeconds(60)); 
      } 

     } 
    } 

    return View(cacheEntry); 
} 

注意を。何百万もの人がいない限り、それは大きな問題ではありません。何百万というものがある場合は、時々ロックコレクションをクリアすることができます。これは安全ではなく、複数のスレッドが保護されたブロックに入ることを許しているかもしれませんが、この具体的なケースではどちらかが問題にはならないようです(高価なデータベース呼び出しを避けるためにロックを使用するためです)。

+0

が妥当と思われます。アプリケーションプールを少なくとも1日1回再起動するため、蓄積は問題にはなりません。ありがとう – Robert

+0

私は参照してください。これは、同じ鍵に対して複数のロックを作成または作成しようとするのを防ぐ方法です。 – Robert

+1

@ロベルト私は上記のコメントが間違っているより多くの思考の後に私は間違っています。怠惰でなくても安全です。遅延のない 'GetOrAdd'の問題は、複数回渡すデリゲートを実行できることです。この場合、同じキーにアクセスしながら複数のAsyncLockを作成することができます。しかし、これらのAsyncLockのうちの1つだけがGetOrAdd呼び出しから返され、もう1つは破棄されます。 AsyncLockは使い捨てではないので、作成され破棄される可能性のある問題はほとんどありません。 – Evk

関連する問題