我有一個包含大量動態內容的ASP.NET應用程序。對於屬於特定客戶的所有用戶來說內容是相同的。爲了減少每個請求所需的數據庫命中數量,我決定緩存客戶端級別的數據。我創建了一個靜態類(「ClientCache」)來保存數據。
該類最常用的方法是迄今爲止的「GetClientData」,它返回包含特定客戶端的所有存儲數據的ClientData對象。不過,客戶端數據會被延遲加載:如果請求的客戶端數據已被緩存,調用者將獲取緩存的數據;否則,數據被提取,添加到緩存中,然後返回給調用者。ASP.NET /靜態類競爭條件?
最終我開始在ClientData對象添加到緩存的行上的GetClientData方法中發生間歇性崩潰。下面是方法體:
public static ClientData GetClientData(Guid fk_client)
{
if (_clients == null)
_clients = new Dictionary<Guid, ClientData>();
ClientData client;
if (_clients.ContainsKey(fk_client))
{
client = _clients[fk_client];
}
else
{
client = new ClientData(fk_client);
_clients.Add(fk_client, client);
}
return client;
}
異常文本總是類似於「具有相同鍵的對象已存在」。 當然,我試圖編寫代碼,這樣如果客戶端已經存在,就無法將客戶端添加到緩存中。
在這一點上,我懷疑我有一個競爭條件,並且該方法正在同時執行兩次,這可以解釋代碼將如何崩潰。但是,我感到困惑的是,該方法如何可以同時執行兩次。據我所知,任何ASP.NET應用程序一次只能處理一個請求(這就是爲什麼我們可以使用HttpContext.Current)。
那麼,這個錯誤可能是一個競爭條件,需要把鎖定在關鍵部分?或者我錯過了一個更明顯的錯誤?
感謝您的解釋。我知道ASP.NET輸出緩存,但不知道緩存對象。緩存API將更加乾淨地解決我的問題。 – mschaad 2009-03-03 06:17:22
只有高速緩存上的原子操作是線程安全的。如果你做了一些事情,比如檢查一個鍵是否存在,然後添加它,那不是線程安全的,並且會導致項被覆蓋。 – 2009-03-04 00:59:29