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


84

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

据我了解,两者都是线程安全的,乍一看API几乎是相同的,那么使用哪个有什么区别?

Answers:


80

HttpRuntime.Cache获取Cache当前应用程序的。

MemoryCache班是类似于ASP.NETCache类。

MemoryCache班有许多属性和访问缓存,如果你已经使用了ASP.NET,这将是你熟悉的方法Cache类。

HttpRuntime.Cache和之间的主要区别MemoryCache是后者已更改为可以被非ASP.NET应用程序的.NET Framework应用程序使用。

如需其他阅读:

更新:

根据用户的反馈,有时乔恩·戴维斯(Jon davis)博客无法正常工作,因此我将整篇文章都放在图片中,请注意。

注意:如果不清楚,请单击图像,然后将其在浏览器中打开,然后再次单击以进行缩放:)

在此处输入图片说明


约翰·戴维斯(John Davis)的那篇文章非常好读-在一个地方就清楚了利弊。
Giedrius 2012年

绝对一切都在一个地方。此外,戴维斯还提到了4种不同的缓存方法。
Sampath

2
@Spikeh对我来说很好。
user247702 2014年

1
@Stijn谢谢,前几天没有加载,但现在又回来了:)
Spikeh 2014年

1
@sampath现在可以使用了。昨天看起来好像该网站已被黑客入侵。谢谢你的帮助!
Baga'3

24

这是乔恩·戴维斯(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 Forms应用程序,ASP.NET缓存可能无法正常工作。

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

Cache cache = System.Web.HttpRuntime.Cache;

与ASP.NET缓存的工作是记录在MSDN上这里

优点:

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

缺点:

  1. 它不仅是静态的,而且只有一个。您无法使用其自己的静态Cache实例创建自己的类型。在整个应用周期内,您只能有一个存储分区。您可以使用自己的包装器来包装存储桶,这些包装器可以执行类似在键中预注入前缀的操作,并在拔出键/值对时删除这些前缀。但是仍然只有一个桶。一切都集中在一起。例如,如果您有一项服务需要分别缓存三种或四种不同类型的数据,则这可能是真正的麻烦。对于可悲的简单项目来说,这不是一个大问题。但是,如果一个项目由于其要求而具有很大程度的复杂性,则ASP.NET缓存通常将不足以满足。
  2. 物品可能会消失,willy-nilly。很多人没有意识到这一点,直到我重新获得有关此缓存实现的知识之前,我才意识到这一点。默认情况下,ASP.NET缓存设计为在“感觉”到喜欢时销毁项目。更具体地说,请参阅本文顶部我对缓存表的定义中的(c)。如果同一进程中的另一个线程正在处理完全不同的事情,并将高优先级项目转储到缓存中,则.NET决定需要使用一些内存后,它将根据以下内容开始销毁缓存中的某些项目:他们的优先事项,低优先事项优先。此处记录的用于添加缓存项的所有示例均使用默认优先级,而不是使用NotRemovable优先级值,该值不会出于清除内存的目的而将其删除,但仍会根据过期策略将其删除。
  3. 密钥必须是字符串。例如,如果要高速缓存数据记录,而这些记录是用长整数或整数键入键的,则必须先将键转换为字符串。
  4. 语法过时。它是.NET 1.0语法,比ArrayList或Hashtable还要难看。这里没有泛型,也没有IDictionary <>接口。它没有Contains()方法,没有Keys集合,没有标准事件;它只有一个Get()方法以及一个与Get()相同的索引器,如果没有匹配项,则返回null,再加上Add(),Insert()(冗余?),Remove()和GetEnumerator() 。
  5. 忽略设置默认过期/删除行为的DRY原则,因此您可以忽略它们。您必须明确告知缓存,希望添加的项目在每次添加添加项目时如何过期或被删除。
  6. 无法访问已缓存项目的缓存详细信息,例如添加时间的时间戳。封装在这里有些过分,当您尝试在代码中尝试确定是否应针对另一种缓存机制(即会话集合)使缓存项无效时,很难使用缓存。
  7. 删除事件不会作为事件公开,必须在添加时进行跟踪。
  8. 而且,如果我还没说清楚的话,Microsoft会明确建议您在网络之外使用它。而且,如果您对.NET 1.1感到困惑,那么您不应该在网络之外的任何地方使用它来确保稳定性,因此不要打扰。

.NET 4.0的ObjectCache / MemoryCache

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

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在Web外部提供支持和推荐。
  2. 与ASP.NET缓存不同,您可以实例化MemoryCache对象实例。

    注意:不一定必须是静态的,而应该是静态的-这是Microsoft的建议(请参阅黄色警告)

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

缺点:

  1. 仍不能完全增强DRY。从我的少量经验来看,您仍然无法一次设置滑动到期时间跨度,而忘了它。坦率地说,尽管以上项添加示例中的策略更具可读性,但它却需要令人恐怖的冗长。
  2. 它仍然不是通用密钥。它需要一个字符串作为键。因此,如果要缓存数据记录,则不能存储long或int,除非转换为字符串。

自己动手做

创建执行显式或滑动到期的缓存字典实际上非常简单。(如果您要自动清除内容以清除内存,则会变得更加困难。)这是您要做的所有事情:

  1. 创建一个名为Expiring或Expirable之类的值容器类,该类将包含类型T的值,将值添加到缓存时要存储的DateTime类型的TimeStamp属性,以及指示距离时间戳有多远的TimeSpan。该项目应过期。对于显式到期,您可以公开一个属性设置器,该设置器在给定日期减去时间戳的情况下设置TimeSpan。
  2. 创建一个实现IDictionary的类,我们称之为ExpirableItemsDictionary。我更喜欢使它成为消费者定义的通用类。
  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()例程,通过替换项目容器(过期实例)上的时间戳(如果已存在)来推出滑动过期。

Microsoft必须支持其原始设计,因为其用户群已经建立了对它们的依赖,但这并不意味着它们是好的设计。

优点:

  1. 您可以完全控制实施。
  2. 可以通过设置默认的缓存行为,然后在每次添加项时都声明键/值对而无需声明缓存详细信息来增强DRY
  3. 可以实现现代化的接口,即IDictionary<K,T>。这使它的使用变得更加容易,因为它的接口像字典接口一样可预测,并且它使与IDictionary <>一起使用的助手和扩展方法更易于使用。
  4. 缓存详细信息可以不封装,例如,通过公共只读属性公开InnerDictionary,允许您针对缓存策略编写显式的单元测试,并使用基于其的其他缓存策略扩展基本的缓存实现。
  5. 尽管对于那些已经熟悉ASP.NET缓存或Caching Application Block的.NET 1.0样式语法的用户来说,它不一定是熟悉的界面,但是您可以定义该界面,使其看起来像您想要的一样。
  6. 可以使用任何类型的键。这是创建泛型的原因之一。并非所有内容都应使用字符串键入。

缺点:

  1. 不是Microsoft发明或认可的,因此不会具有相同的质量保证。
  2. 假设仅执行了上面描述的指令,不会“故意”清除优先级清除内存的项目(无论如何这都是缓存的特殊功能。.在要使用缓存的地方购买RAM ,RAM很便宜)。

在所有这四个选项中,这是我的偏爱。我已经实现了这个基本的缓存解决方案。到目前为止,它似乎运行良好,没有已知的错误(请与我联系,并提供下面的评论;如果有,请联系jon-at-jondavis!),我打算在所有需要的小型项目中使用它基本缓存。这里是:

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

旧链接:ExpirableItemDictionary.zip

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

请注意,此博客文章的标题指示“简单缓存”,而不是“重型缓存”。如果您想了解重型产品,则应查看专用的横向扩展解决方案。



3

它说的是MemoryCache,即存储在内存中的缓存

HttpRuntime.Cache(请参见http://msdn.microsoft.com/zh-cn/library/system.web.httpruntime.cache(v=vs.100).aspxhttp://msdn.microsoft.com/zh-我们/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


1
嗯,不确定第二个链接是否不会引起误解,因为正在谈论OutputCache和实现OutputCacheProvider。
Giedrius 2012年

嗯,我找不到它能说的话,您可以使用其他配置来保留System.Web.Caching.Cache
Giedrius 2012年

2

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

我还写了一个小的基准来存储一个bool项目20000次(以及另一个基准来检索它),而MemoryCache似乎慢了两倍(27ms与13ms-这是所有20k迭代的总和),但是它们都非常快,而且可能会被忽略。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.