访问和更新缓存字典

时间:2015-04-01 18:30:04

标签: c# asp.net .net concurrency

我有一个Dictionary(并发),用于将一个对象id映射到另一个。根据输入键获取值id相当昂贵,因此我希望将字典保留在服务器缓存中。

我首先尝试了一种方法来做到这一点,但它只是“觉得”可能有更好的方法来做到这一点:

private string GetItem(string cacheKey, string itemKey)
{
    string sfAccountId = null;
    ConcurrentDictionary<string, string> sfAccountMap =
            Context.Cache[cacheKey] as ConcurrentDictionary<string, string>;
    if(sfAccountMap == null)
    {
        lock(cacheLock)
        {
            sfAccountMap = Context.Cache[cacheKey] as ConcurrentDictionary<string, string>;
            if(sfAccountMap == null)
            {
                sfAccountMap = new ConcurrentDictionary<string, string>();
                sfAccountId = ExpensiveMethodReturnsString();
                if(!String.IsNullOrEmpty(sfAccountId))
                {
                    sfAccountMap.TryAdd(itemKey, sfAccountId);
                }
                Context.Cache[cacheKey] = sfAccountMap;
            }
        }
    }
    else
    {
        if(sfAccountMap.ContainsKey(itemKey))
        {
            sfAccountMap.TryGetValue(itemKey, out sfAccountId);
        }
        else
        {
            sfAccountMap.TryAdd(itemKey, ExpensiveMethodReturnsString());
            lock(cacheLock)
            {
                Context.Cache[cacheKey] = sfAccountMap;
            }
        }
    }
    return sfAccountId;
}

1 个答案:

答案 0 :(得分:1)

看起来您的代码可以简化,同时仍然可以执行它现在正在执行的操作。

private ConcurrentDictionary<string, string> GetCachedAccountMap(string cacheKey)
{
    var map = Context.Cache[cacheKey] as ConcurrentDictionary<string, string>;
    if (map == null) 
    {
        lock (cacheLock) 
        {
            map = Context.Cache[cacheKey] as ConcurrentDictionary<string, string>;
            if (map == null)
                map = Context.Cache[cacheKey] = new ConcurrentDictionary<string, string>();
        }
    }
    return map;
}

private string GetItem(string cacheKey, string itemKey)
{
    return GetCachedAccountMap(cacheKey)
        .GetOrAdd(itemKey, k => ExpensiveMethodReturnsString());
}

注意:鉴于帐户映射尚不存在时,不太可能同时访问缓存,并且在非常特殊的情况下,如果您执行一次额外的分配并调用昂贵的方法,GetCachedAccountMap方法可以通过不使用任何锁来进一步简化。

private ConcurrentDictionary<string, string> GetCachedAccountMap(string cacheKey)
{
    var map = Context.Cache[cacheKey] as ConcurrentDictionary<string, string>;
    if (map == null) 
        map = Context.Cache[cacheKey] = new ConcurrentDictionary<string, string>();
    return map;
}