1
我有代碼,當前沒有線程安全的一個故事:與ASP.Net緩存保證線程安全 - 兩種策略
public byte[] GetImageByteArray(string filepath, string contentType, RImgOptions options)
{
//Our unique cache keys will be composed of both the image's filepath and the requested width
var cacheKey = filepath + options.Width.ToString();
var image = HttpContext.Current.Cache[cacheKey];
//If there is nothing in the cache, we need to generate the image, insert it into the cache, and return it
if (image == null)
{
RImgGenerator generator = new RImgGenerator();
byte[] bytes = generator.GenerateImage(filepath, contentType, options);
CacheItem(cacheKey, bytes);
return bytes;
}
//Image already exists in cache, serve it up!
else
{
return (byte[])image;
}
}
我CacheItem()
方法檢查,看看它的最大緩存大小已經達成,並如果有,它會開始刪除緩存的項目:
//If the cache exceeds its max allotment, we will remove items until it falls below the max
while ((int)cache[CACHE_SIZE] > RImgConfig.Settings.Profile.CacheSize * 1000 * 1000)
{
var entries = (Dictionary<string, DateTime>)cache[CACHE_ENTRIES];
var earliestCacheItem = entries.SingleOrDefault(kvp => kvp.Value == entries.Min(d => d.Value));
int length = ((byte[])cache[earliestCacheItem.Key]).Length;
cache.Remove(earliestCacheItem.Key);
cache[CACHE_SIZE] = (int)cache[CACHE_SIZE] - length;
}
由於另一個線程引用它的一個線程可以從緩存中刪除一個項目,我能想到的兩個選項:
選項1:鎖定
lock (myLockObject)
{
if(image == null){ **SNIP** }
}
選項2:指定一個淺拷貝到一個局部變量
var image = HttpContext.Current.Cache[cacheKey] != null ? HttpContext.Current.Cache[cacheKey].MemberwiseClone() : null;
這兩種選擇都有開銷。第一個強制線程一次輸入一個代碼塊。第二個需要在內存中創建一個可能不重要的新對象。
我可以在這裏聘請其他任何策略嗎?
我沒有看到這個代碼的問題。據我所知,從緩存中刪除項目不會處理它。因此,從緩存中刪除它只會刪除引用。引用它的對象應該不受影響,除非您明確地處理它。Cache本身是線程安全的,所以在查找時不必擔心被刪除的對象。 –
你也知道你可以在你的web.config中設置緩存的最大大小?當達到這個大小時,asp.net本身就會開始修剪緩存?我不知道爲什麼你覺得自己需要這樣做... –
@ErikFunkenbusch我相信你說的是真實的,本地'image'變量將持有一個引用,使緩存指向的對象不符合條件爲垃圾收集。我在看一個沒有使用局部變量(但可能應該是)的例子,而是在兩個單獨的操作中重新查詢緩存,因此使用了鎖。無論如何,謝謝你明確表示我不需要兩個不吃人吃的選項。 –