停止缓存的双重加载

Stop double loading of cache

给出从数据库加载所有可用语言的代码(仅用作示例):

/// <summary>
/// Dictionary of all languages
/// </summary>
private static Dictionary<int, Language> GetLanguagesDictionary()
{
    const string cacheIndex = Settings.CachePrefix + "LanguagesDictionary";
    var context = HttpContext.Current;
    if (context.Cache[cacheIndex] == null)
    {
        var dict = new Dictionary<int, Language>();
        using (var db = new DBContext())
        {
            var q = db.Languages;
            foreach (var rec in q)
            {
                dict.Add(rec.ID, new Language(rec));
            }
        }
        context.Cache.Add(cacheIndex, dict, null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);
    }
    return (Dictionary<int, Language>) context.Cache[cacheIndex];
}

如果将记录加载到缓存中的代码需要一段时间才能完成,并且有另一个页面请求进来,它会抛出异常并导致一些问题。

修改上述代码以使其安全应对这种情况的最佳方法是什么?

您可以使用Lazy<T>

static Lazy<Dictionary<int, Language>> GetLanguage = 
      new Lazy<Dictionary<int, Language>>(() => GetLanguagesDictionary(), true);

现在您将在代码中使用 GetLanguage.Value..

更新

您的最终代码将与此类似:

private static Dictionary<int, Language> GetLanguagesDictionary()
{
        var dict = new Dictionary<int, Language>();
        using (var db = new DBContext())
        {
            var q = db.Languages;
            foreach (var rec in q)
            {
                dict.Add(rec.ID, new Language(rec));
            }
        }
        return dict;
}

public static Lazy<Dictionary<int, Language>> GetLanguages = 
    new Lazy<Dictionary<int, Language>>(() => GetLanguagesDictionary(), true);

您必须使用 lock 同步缓存的写入和创建:

///
/// for locking synhronize
///
private static readonly object syncLock = new object();

/// <summary>
/// Dictionary of all languages
/// </summary>
private static Dictionary<int, Language> GetLanguagesDictionary()
{
    const string cacheIndex = Settings.CachePrefix + "LanguagesDictionary";
    var context = HttpContext.Current;

    if (context.Cache[cacheIndex] == null)
    {
        lock (syncLock)
        {
            if (context.Cache[cacheIndex] == null)
            {
                var dict = new Dictionary<int, Language>();
                using (var db = new DBContext())
                {
                    var q = db.Languages;
                    foreach (var rec in q)
                    {
                        dict.Add(rec.ID, new Language(rec));
                    }
                }
                context.Cache.Add(cacheIndex, dict, null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);
            }
        }
    }
    return (Dictionary<int, Language>)context.Cache[cacheIndex];
}