2012-08-09 48 views
2

這是情景:ASP.Net緩存和鎖的高流量網站

  • 線程A的所有書籍問法國

  • 線程B要求所有書籍阿拉伯語

如果線程A在鎖區域,線程B將在線程A的鎖區域外等待完成。

因爲線程B可以獲取他的數據的代碼中只有一個「地方」。

我想使基於緩存的關鍵這意味着這樣的鎖:

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

我認爲雙鎖不是很好...... 你看到任何其他的解決方案/改進?

+0

AFAIK,鎖不適用於不頻繁更改i-e的只讀對象。在您的阿拉伯語案例書中可能不會頻繁更改,所以我的觀點是您爲什麼使用鎖來讀取實時沒有變化的數據? – 2012-08-09 09:35:44

+0

即使它不經常改變,它可能會在錯誤的時刻改變。無論*可能*出錯*將會出錯。 – 2012-08-09 09:42:54

+0

@Furqan:因爲(大概)讀取數據('GetFromDB()')是一個相對昂貴的(時間上的)操作,這就是它被緩存的原因。 – 2012-08-15 15:32:19

回答

0

它可能只是在您的示例僞代碼,但locking on objects is recommended over strings(由於更低級別的優化如不可變的共享字符串,規範版本等 - 參見Locking by string. Is this safe/sane?)。

對於單一,號稱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代替了哈希表(如your pastebin code所示) - 它可以節省你從一個額外的「鎖定級別」。神奇的發生在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; 
     } 
} 
+0

如果將此與動態生成的密鑰一起使用,ConcurrentDictionary將隨着時間的推移而增長和增長,因爲永遠不會清理鎖,儘管這可能不成問題。兩種解決方案可能是1.刪除cacheexpirycallback中的鎖定對象(但這會產生一些棘手的競爭條件),或者2.使用ConditionalWeakTable而不是字典(但這意味着在CWT中使用字符串鍵,這似乎是皺眉在..) – mcintyre321 2014-08-18 10:17:55