在asp.net mvc应用程序中进行缓存时,我们真的需要锁定吗?

时间:2015-10-11 15:18:22

标签: asp.net-mvc caching locking httpcontext

我看到很多缓存示例包括锁定。我正在尝试缓存整个应用程序的常用列表。我真的需要使用下面的锁吗?如果我不使用锁定就会发生最糟糕的事情;

如果多个线程几乎同时检测到缓存未命中。他们可能会同时尝试加载数据。总之,数据将是相同的......

是真的吗?

 public class Worker

{

    private static object someLock;

    public static object CacheMethod()
    {

        var results = HttpContext.Current.Cache["Common"];

        if (results == null)
        {
            lock (someLock)
            {
                results = HttpContext.Current.Cache["Common"];
                if (results == null)
                {
                    results = GetResultsFromSomewhere();
                    HttpContext.Current.Cache.Insert("Common", results, null,
                            DateTime.Now.AddHours(1), Cache.NoSlidingExpiration);
                }
            }
        }
        return results;

    }``

2 个答案:

答案 0 :(得分:1)

此锁用于防止缓存加盖。如果缓存为空并且需要一段时间来填充,则所有传入的请求将开始填充缓存。取决于数字如何计算,这可能是灾难性的性能损失。

如果GetResultsFromSomewhereThread.Sleep(10000),则很容易发生这种情况。

该特定代码的坏处是它是所有缓存键的一个锁。通常你想要每把钥匙锁一次。

答案 1 :(得分:0)

这称为double-checked locking pattern。是的,如果你有很多请求并且数据检索的时间比请求之间的时间长,那么你可以对同一数据提出多个请求。

如果没有锁定,每个附加线程都会接收相同的数据,因此额外线程使用的CPU /网络活动/ RAM量就会被浪费掉。这是否是一个问题取决于您的网站拥有多少流量以及可用的服务器/网络资源。

但是,确保您的results对象本身是线程安全的更为重要,因为您可以保证多个线程与其状态交互。最简单的方法是将所有属性设置为只读,但如果需要可写属性,可以将ReaderWriterLockSlim与确保原子操作的方法结合使用(参见链接中的示例)。