Doing locking in ASP.NET correctly

后端 未结 3 720
广开言路
广开言路 2020-12-29 14:40

I have an ASP.NET site with a fairly slow search function, and I want to improve performance by adding the results to the cache for one hour using the query as the cache-key

3条回答
  •  时光取名叫无心
    2020-12-29 15:08

    Unless you're absolutely certain that it's critical to have no redundant queries then I would avoid locking altogether. The ASP.NET cache is inherently thread-safe, so the only drawback to the following code is that you might temporarily see a few redundant queries racing each other when their associated cache entry expires:

    public static string DoSearch(string query)
    {
        var results = (string)HttpContext.Current.Cache[query];
        if (results == null)
        {
            results = GetResultsFromSlowDb(query);
    
            HttpContext.Current.Cache.Insert(query, results, null,
                DateTime.Now.AddHours(1), Cache.NoSlidingExpiration);
        }
        return results;
    }
    

    If you decide that you really must avoid all redundant queries then you could use a set of more granular locks, one lock per query:

    public static string DoSearch(string query)
    {
        var results = (string)HttpContext.Current.Cache[query];
        if (results == null)
        {
            object miniLock = _miniLocks.GetOrAdd(query, k => new object());
            lock (miniLock)
            {
                results = (string)HttpContext.Current.Cache[query];
                if (results == null)
                {
                    results = GetResultsFromSlowDb(query);
    
                    HttpContext.Current.Cache.Insert(query, results, null,
                        DateTime.Now.AddHours(1), Cache.NoSlidingExpiration);
                }
    
                object temp;
                if (_miniLocks.TryGetValue(query, out temp) && (temp == miniLock))
                    _miniLocks.TryRemove(query);
            }
        }
        return results;
    }
    
    private static readonly ConcurrentDictionary _miniLocks =
                                      new ConcurrentDictionary();
    

提交回复
热议问题