System.Runtime.Caching.MemoryCache vs HttpRuntime.Cache - 有什么区别吗?

时间:2012-12-04 13:26:12

标签: c# asp.net-mvc c#-4.0 caching

我想知道MemoryCacheHttpRuntime.Cache之间是否存在任何差异,哪一个在ASP.NET MVC项目中是首选?

据我了解,两者都是线程安全的,API乍一看或多或少相同,所以使用时有什么区别吗?

4 个答案:

答案 0 :(得分:77)

HttpRuntime.Cache获取当前应用的Cache

MemoryCache类类似于ASP.NET Cache类。

如果您使用了ASP.NET MemoryCache类,Cache类有许多用于访问缓存的属性和方法。

HttpRuntime.CacheMemoryCache之间的主要区别在于后者已被更改为可供非ASP.NET应用程序的.NET Framework应用程序使用。

进一步阅读:

更新:

根据用户的反馈,有时Jon davis博客不起作用。因此我把整篇文章都作为一个图像。请看。

注意:如果不清楚则只需点击图片。之后它会在浏览器上打开。然后再次点击它来缩放:)

enter image description here

答案 1 :(得分:21)

这是Jon Davis'文章。为了保持可读性,我要删除现在过时的EntLib部分,介绍和结论。

ASP.NET缓存

ASP.NET或System.Web.dll程序集确实有一个缓存机制。它从来没有打算在Web上下文之外使用,但它可以在Web之外使用,并且它确实在各种哈希表中执行所有上述过期行为。

在搜索Google之后,似乎有不少人讨论过.NET中的内置缓存功能,他们已经在非Web项目中使用了ASP.NET缓存。这不再是.NET中最可用,最受支持的内置缓存系统; .NET 4有一个ObjectCache,我将在稍后介绍。 Microsoft一直坚持认为ASP.NET缓存不适合在Web之外使用。但很多人仍然停留在.NET 2.0和.NET 3.5中,需要一些工作,这对许多人来说都很有用,尽管MSDN说得很清楚:

  

注意:Cache类不适用于ASP.NET应用程序之外。它的设计和测试用于ASP.NET,以便为Web应用程序提供缓存。在其他类型的应用程序中,例如控制台应用程序或Windows窗体应用程序,ASP.NET缓存可能无法正常工作。

ASP.NET缓存的类是System.Web.dll中的System.Web.Caching.Cache。但是,您不能简单地新建一个Cache对象。您必须从System.Web.HttpRuntime.Cache。

获取它
Cache cache = System.Web.HttpRuntime.Cache;

MSDN here上记录了使用ASP.NET缓存。

优点:

  1. 内置
  2. 尽管使用了.NET 1.0语法,但使用它还是简单
  3. 在网络环境中使用时,经过充分测试。除了网络上下文之外,根据谷歌的搜索结果,只要你使用的是.NET 2.0或更高版本,尽管微软建议反对它,但通常不会引起问题。
  4. 删除某个项目后,您可以通过代理通知,如果您需要将其保持活动状态并且无法提前设置该项目的优先级,则必须这样做。
  5. 在本文顶部的删除方法列表中,(a),(b)或(c)到期和删除方法中的任何一个项具有灵活性。您还可以将过期行为与物理文件的存在相关联。
  6. 缺点:

    1. 不仅是静态的,只有一个。您无法使用自己的静态Cache实例创建自己的类型。您的整个应用只能拥有一个存储桶。您可以使用自己的包装器来包装存储桶,这些包装器会在按键中预先注入前缀,并在将键/值对拉回时删除这些前缀。但仍然只有一个桶。一切都集中在一起。例如,如果您的服务需要分别缓存三种或四种不同类型的数据,那么这可能会非常麻烦。对于可怜的简单项目来说,这不应该是一个大问题。但是,如果一个项目由于其要求而具有任何显着的复杂程度,那么ASP.NET缓存通常是不够的。
    2. 项目可以消失,不知不觉。很多人都没有意识到这一点 - 我不知道,直到我刷新了我对这个缓存实现的了解。默认情况下,ASP.NET缓存旨在销毁“感觉”类似的项目。更具体地说,请参阅我在本文顶部的缓存表定义中的(c)。如果同一进程中的另一个线程正在处理完全不同的事情,并且它将高优先级项目转储到缓存中,那么一旦.NET决定它需要一些内存,它就会开始销毁缓存中的一些项目。他们的优先事项,首先是低优先此处记录的用于添加缓存项的所有示例都使用默认优先级,而不是NotRemovable优先级值,该值不会为了内存清除目的而将其删除,但仍会根据到期策略将其删除。缓存调用中的Peppering CacheItemPriority.NotRemovable可能很麻烦,否则需要包装器。
    3. 密钥必须是字符串。例如,如果要缓存记录以长整数或整数键入的数据记录,则必须先将密钥转换为字符串。 / LI>
    4. 语法陈旧。它是.NET 1.0语法,甚至比ArrayList或Hashtable更丑陋。这里没有泛型,没有IDictionary<>接口。它没有Contains()方法,没有Keys集合,没有标准事件;它只有一个Get()方法加上一个与Get()做同样事情的索引器,如果没有匹配则返回null,加上Add(),Insert()(冗余?),Remove()和GetEnumerator()
    5. 忽略设置默认过期/删除行为的DRY原则,以便您可以忘记它们。您必须明确告诉缓存您希望添加的项目如何到期或在每次添加项目时删除。
    6. 无法访问缓存项目的缓存详细信息,例如添加时间戳的时间戳。封装在这里有点过分,在代码中你很难使用缓存,你试图确定缓存的项目是否应该与另一个缓存机制(即会话集合)无效。
    7. 删除事件不会作为事件公开,必须在添加时进行跟踪。
    8. 如果我说得不够,Microsoft explicitly recommends against it在网络之外。如果你在网络之外被.NET 1.1, you not supposed to use it with any confidence of stability at all诅咒,那就不要打扰了。
    9. .NET 4.0的ObjectCache / MemoryCache

      Microsoft最终在最新版本的.NET Framework中实现了一个抽象的ObjectCache类,以及一个在非Web设置中为内存目的继承和实现ObjectCache的MemoryCache实现。

      System.Runtime.Caching.ObjectCache位于System.Runtime.Caching.dll程序集中。它是一个抽象类,它声明了与ASP.NET缓存中基本相同的.NET 1.0样式接口。 System.Runtime.Caching.MemoryCache是ObjectCache的内存中实现,与ASP.NET缓存非常相似,但有一些变化。

      要添加具有滑动过期的项目,您的代码将如下所示:

      var config = new NameValueCollection();  
      var cache = new MemoryCache("myMemCache", config);  
      cache.Add(new CacheItem("a", "b"),  
          new CacheItemPolicy  
          {  
              Priority = CacheItemPriority.NotRemovable,  
              SlidingExpiration=TimeSpan.FromMinutes(30)  
          }); 
      

      优点:

      1. 它是内置的,现在由Microsoft以外的网络支持和推荐。
      2. 与ASP.NET缓存不同,您可以实例化MemoryCache对象实例。

          

        注意:它不必是静态的,但它应该是 - Microsoft’s recommendation (see yellow Caution)

      3. 对ASP.NET缓存的界面进行了一些细微的改进,例如订阅删除事件的能力,而不必在添加项目时删除,冗余的Insert()被删除,项目可以使用CacheItem对象添加一个定义缓存策略的初始化程序,并添加Contains()。

      4. 缺点:

        1. 仍然没有完全强化DRY。根据我的少量经验,您仍然无法设置一次滑动到期TimeSpan而忘记它。坦率地说,虽然上面的项目添加示例中的政策更具可读性,但它需要可怕的冗长。
        2. 它仍然没有通用键;它需要一个字符串作为键。因此,如果要缓存数据记录,则不能存储long或int,除非转换为字符串。
        3. DIY:自己建造

          创建一个执行显式或滑动过期的缓存字典实际上非常简单。 (如果您希望自动删除项目以进行内存清除,则会变得更加困难。)以下是您需要做的所有事情:

          1. 创建一个名为Expiring或Expirable的值容器类,它包含一个类型为T的值,一个TimeStamp属性,类型为DateTime,当该值被添加到缓存时存储,以及一个TimeSpan,它指示距离多远项目应该到期的时间戳。对于显式到期,您可以公开一个属性设置器,该设置器设置TimeSpan,并给出一个减去时间戳的日期。
          2. 创建一个类,我们称之为ExpirableItemsDictionary,它实现了IDictionary。我更喜欢把它变成一个由消费者定义的泛型类。
          3. 在#2中创建的类中,添加一个Dictionary>作为一个属性并称之为InnerDictionary。
          4. 如果在#2中创建的类中的IDictionary应该使用InnerDictionary来存储缓存的项目。封装将通过上面#1中创建的类型的实例隐藏缓存方法细节。
          5. 确保索引器(this []),ContainsKey()等在返回值之前小心清除过期的项目并删除过期的项目。如果项目已被删除,则在getter中返回null。
          6. 在所有getter,setter,ContainsKey()上使用线程锁,尤其是在清除过期项目时。
          7. 每当项目因到期而被删除时,都会举起活动。
          8. 添加System.Threading.Timer实例并在初始化期间对其进行装配,以便每15秒自动删除过期的项目。这与ASP.NET缓存的行为相同。
          9. 您可能希望添加一个AddOrUpdate()例程,该例程通过替换项目容器(Expiring instance)上的时间戳(如果它已经存在)来推出滑动过期。
          10. 微软必须支持其原始设计,因为它的用户群已经建立了对它们的依赖,但这并不意味着它们是好的设计。

            优点:

            1. 您对实施完全控制
            2. 可以强化DRY ,方法是设置默认缓存行为,然后只需删除键/值对,而不必在每次添加项目时声明缓存详细信息。
            3. 可以实施现代接口,即IDictionary<K,T>。这使得它更容易使用,因为它的界面作为字典界面更容易预测,而且它使得使用IDictionary&lt;&gt;的帮助程序和扩展方法更容易访问。
            4. 缓存详细信息可以解包,例如通过公共只读属性公开您的InnerDictionary,允许您针对缓存策略编写显式单元测试,以及扩展基本缓存实现在其基础上构建的其他缓存策略。
            5. 虽然对于那些已经熟悉ASP.NET缓存或缓存应用程序块的.NET 1.0样式语法的人来说,它不一定是熟悉的界面,但可以定义界面看起来好像你希望它看起来。
            6. 可以使用任何类型的键。这就是为什么创建泛型的原因之一。并非一切都应该用字符串键入。
            7. 缺点:

              1. 不是由Microsoft发明,也不是由Microsoft认可,因此不会有相同的质量保证。
              2. 假设只实现了我上面描述的指令,那么“willy-nilly”不会清除优先清理内存的项目(无论如何都是缓存的角落效用函数..购买RAM你会在哪里使用缓存,RAM便宜)。
              3. 在所有这四个选项中,这是我的偏好。我已经实现了这个基本的缓存解决方案。到目前为止,它似乎工作得很好,没有已知的错误(如果有!!请在下面或jon-at-jondavis与我联系),我打算在我需要的所有较小的项目中使用它基本缓存。这是:

                Github链接:https://github.com/kroimon/ExpirableItemDictionary

                旧链接:ExpirableItemDictionary.zip

                值得一提的是:AppFabric,NoSQL,Et Al

                请注意,此博客文章的标题表示“简单缓存”,而不是“重载缓存”。如果你想深入了解重要的事情,你应该看看专门的,扩展的解决方案。

答案 2 :(得分:3)

MemoryCache就是它所说的,一个存储在内存

中的缓存

HttpRuntime.Cache(请参阅http://msdn.microsoft.com/en-us/library/system.web.httpruntime.cache(v=vs.100).aspxhttp://msdn.microsoft.com/en-us/library/system.web.caching.cache.aspx)会一直存在于您在应用程序中配置它的任何内容。

参见例如“ASP.NET 4.0:编写自定义输出缓存提供程序” http://weblogs.asp.net/gunnarpeipman/archive/2009/11/19/asp-net-4-0-writing-custom-output-cache-providers.aspx

答案 3 :(得分:2)

如果要将经典的ASP.NET MVC应用程序迁移到ASP.NET Core,则MemoryCache.Default也可以充当“桥梁”,因为Core中没有“ System.Web.Caching”和“ HttpRuntime”。 / p>

我还写了一个小型基准来存储20000次bool项目(以及另一个用于检索它的基准),而MemoryCache似乎要慢两倍(27ms vs 13ms-总计)对于所有20k迭代),但它们都非常快,因此可以忽略。