System.Runtime.Caching.MemoryCache vs HttpRuntime.Cache – 有什么区别吗?
我想知道在MemoryCache
和HttpRuntime.Cache
之间是否存在任何差异,哪一个在ASP.NET MVC项目中是首选?
据我所知,两者都是线程安全的,API是一见钟情,所以有什么区别何时使用?
HttpRuntime.Cache
获取当前应用程序的Cache
。
MemoryCache
类与ASP.NET Cache
类相似。
如果您使用了ASP.NET Cache
类,则MemoryCache
类具有许多访问caching的属性和方法,这些属性和方法对您来说是熟悉的。
HttpRuntime.Cache
和MemoryCache
之间的主要区别在于后者已被更改为使其可用于不是ASP.NET应用程序的.NET Framework应用程序。
如需更多阅读:
- Justin Mathew博客 – caching在.NET 4.0中
- Jon Davis博客 – .NET中简单caching的四种方法
更新:
根据用户的反馈,有时候Jon Davis博客不工作。因此,我把整篇文章作为一个图像。请看。
注意:如果不清楚,只需点击图像。之后,它会打开浏览器。然后再次点击它放大:)
这是Jon Davis的文章。 为了保持可读性,我删除了现在已经过时的EntLib部分,介绍以及结论。
ASP.NETcaching
ASP.NET或System.Web.dll程序集确实有一个caching机制。 它从来没有打算在web上下文之外使用,但是它可以在web之外使用,并且它可以在一个哈希表中执行所有的上述到期行为。
在Google淘金之后,似乎有不less人在.NET中讨论过内置的cachingfunction,他们已经在非web项目中使用了ASP.NETcaching。 这不再是.NET中最可用,支持最多的内置caching系统; .NET 4有一个ObjectCache,我将在稍后介绍。 微软一直坚持认为,ASP.NETcaching并不打算在networking之外使用。 但是很多人仍然陷在.NET 2.0和.NET 3.5中,需要一些东西来处理,而这恰好适用于很多人,即使MSDN明确地说过:
注意:caching类不打算在ASP.NET应用程序之外使用。 它的devise和testing是为了在ASP.NET中使用,为Web应用程序提供caching。 在其他types的应用程序中,如控制台应用程序或Windows窗体应用程序,ASP.NETcaching可能无法正常工作。
ASP.NETcaching的类是System.Web.dll中的System.Web.Caching.Cache。 但是,不能简单地新build一个Cache对象。 你必须从System.Web.HttpRuntime.Cache获取它。
Cache cache = System.Web.HttpRuntime.Cache;
使用ASP.NETcaching在MSDN中logging在这里 。
优点:
- 它是内置的 。
- 尽pipe.NET 1.0语法,使用起来相当简单 。
- 当在networking环境中使用时,它是经过充分testing的 。 除了networking环境之外,根据谷歌search,尽pipe微软推荐它,但只要您使用的是.NET 2.0或更高版本,通常不会导致问题。
- 当物品被移除时,您可以通过委托人进行通知 ,如果需要保留该物品并且无法事先设置物品的优先级,则这是必要的。
- 单个项目具有 (a),(b)或(c)在本文顶部的清除方法列表中的过期和清除方法的灵活性 。 您还可以将到期行为与物理文件的存在相关联。
缺点:
- 它不仅是静态的,而且只有一个 。 您无法使用自己的caching的静态实例创build自己的types。 您的整个应用程序只能有一个存储桶。 您可以用自己的包装器来包装桶,这些包装器可以在键中预先注入前缀,并在您将键/值对拉回时除去这些前缀。 但仍然只有一个桶。 一切都集中在一起。 例如,如果您有需要分别caching三种或四种不同数据的服务,这可能是一个真正的麻烦。 这对于简单的项目来说不应该是一个大问题。 但是,如果一个项目由于其要求而具有相当程度的复杂性,那么ASP.NETcaching通常是不够的。
- 物品可以消失,无所畏惧 。 很多人都没有意识到这一点 – 我没有,直到我刷新了我对这个caching实现的知识。 默认情况下,ASP.NETcaching旨在在“感觉”喜欢它时销毁项目。 更具体地说,参见本文顶部caching表的定义(c)。 如果同一进程中的另一个线程正在处理完全不同的内容,并且将高优先级的项目转储到caching中,则.NET一旦决定需要某些内存,它就会开始销毁caching中的某些项目他们的优先事项,低优先事项。 这里logging的用于添加caching项目的所有示例都使用默认优先级,而不是为了内存清除目的而被删除的不可移除优先级值,但仍将根据过期策略将其删除。 caching调用中的cachingCacheItemPriority.NotRemovable可能非常麻烦,否则需要封装。
- 密钥必须是一个string。 例如,如果您正在caching数据logging,其中的logging被键入长整数或整数,则必须先将该键转换为string。
- 语法是陈旧的 。 它是.NET 1.0语法,甚至比ArrayList或Hashtable更丑。 这里没有generics,没有IDictionary <>接口。 它没有Contains()方法,没有Keys集合,没有标准事件; 它只有一个Get()方法和一个和Get()完全相同的索引器,如果没有匹配,则返回null,再加上Add(),Insert()(冗余?),Remove()和GetEnumerator() 。
- 忽略设置默认到期/移除行为的DRY原则 ,以便您可以忘记它们。 您必须明确地告诉caching您要添加的项目过期或每次添加项目时将其删除。
- 无法访问caching项目的caching详细信息 ,例如添加时间戳的时间戳。 封装在这里有点过分了,在代码中,当你试图确定一个caching项是否应该与另一个caching机制(即会话集合)无效时,很难使用caching。
- 移除事件不作为事件公开,必须在添加时进行跟踪。
- 如果我没有说足够的话, 微软明确地build议在networking之外不要这样做。 如果你被.NET 1.1所诅咒,那么你不应该在web以外的任何地方使用它来保持稳定性,所以不要打扰。
.NET 4.0的ObjectCache / MemoryCache
Microsoft终于在最新版本的.NET Framework中实现了一个抽象的ObjectCache类,以及一个MemoryCache实现,该实现在非Web设置中inheritance并实现了ObjectCache用于内存目的。
System.Runtime.Caching.ObjectCache位于System.Runtime.Caching.dll程序集中。 这是一个抽象类,它声明基本上在ASP.NETcaching中find的相同的.NET 1.0样式的接口。 System.Runtime.Caching.MemoryCache
是ObjectCache的内存中实现,与ASP.NETcaching非常相似,但有一些变化。
要添加滑动到期的项目,您的代码将如下所示:
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) });
优点:
- 它是内置的,现在受到networking之外的Microsoft的支持和推荐。
-
与ASP.NETcaching不同,您可以实例化一个MemoryCache对象实例。
注意:它不一定是静态的,但它应该是 – 这是微软的build议(见黄色注意) 。
-
与ASP.NETcaching的接口相比,有一些细微的改进,例如订阅删除事件的能力,而不需要添加项目,删除多余的Insert(),可以通过CacheItem添加项目使用定义caching策略的初始化程序对象,并添加了Contains()。
缺点:
- 仍然不完全强化干燥。 从我的经验less量,你仍然不能设置滑动到期TimeSpan一次,忘掉它。 坦率地说,尽pipe上面的样本添加样本的策略更具可读性,但它需要可怕的冗长。
- 它仍然不是通用键。 它需要一个string作为关键。 所以如果你正在caching数据logging,那么你不能存储long或int,除非你转换为string。
DIY:build立一个自己
创build一个执行显式或滑动过期的caching字典实际上非常简单。 (如果你想要为了内存清理的目的而自动移除项目,这会变得更加困难。)以下是你所要做的:
- 创build一个名为“Expiring”或“Expirable”的值容器类,其中包含typesT的值,types为DateTime的TimeStamp属性,用于在将值添加到caching时进行存储,以及一个TimeSpan,表示距离时间戳该项目应该过期。 对于明确的过期,您可以公开一个属性设置器,该属性设置器将TimeSpan设置为由时间戳减去的date。
- 创build一个类,我们称之为ExpirableItemsDictionary,它实现了IDictionary。 我更喜欢使它成为消费者定义的通用类。
- 在#2中创build的类中,添加一个Dictionary>作为属性,并将其称为InnerDictionary。
- 如果在#2中创build的类中的IDictionary应该使用InnerDictionary存储caching的项目,则实现。 封装将通过上面#1中创build的types的实例来隐藏caching方法的细节。
- 确保索引器(this []),ContainsKey()等等在返回值之前仔细清除已过期的项目并删除已过期的项目。 如果项目被删除,则在getters中返回null。
- 在所有获取者,设置者,ContainsKey()上使用线程锁,特别是在清除已过期的项时。
- 每当物品由于到期而被移除时引发一个事件。
- 添加一个System.Threading.Timer实例并在初始化期间使用它来每隔15秒自动删除过期的项目。 这与ASP.NETcaching的行为相同。
- 您可能需要添加一个AddOrUpdate()例程,通过replace项目容器上的时间戳(过期实例)(如果它已经存在)来推出滑动过期。
微软必须支持它的原始devise,因为它的用户基础已经build立了对它们的依赖,但这并不意味着它们是好的devise。
优点:
- 您可以完全控制实施。
- 可以通过设置默认的caching行为来加强DRY ,然后只需删除键/值对,而无需在每次添加项目时都声明caching详细信息。
- 可以实现现代接口 ,即
IDictionary<K,T>
。 这使得它更易于使用,因为它的接口作为一个字典接口更具可预测性,而且使得它更容易被IDictionary <>使用的助手和扩展方法访问。 - caching细节可以解封装 ,比如通过公开的只读属性暴露你的InnerDictionary,允许你写出明确的caching策略的unit testing,以及基于它的附加caching策略扩展你的基本caching实现。
- 虽然对于那些已经习惯了ASP.NETcaching或caching应用程序块的.NET 1.0风格语法的用户来说,它并不是一个熟悉的界面,但您可以将界面定义为您希望的样子。
- 可以使用任何types的键。 这是仿制药创build的一个原因。 不是所有的东西都应该用string键入。
缺点:
- 不是由微软发明的,也不是由微软认可的,所以它不会有相同的质量保证。
- 假设只有上面描述的指令被执行,并不是“无所谓”的清除项目,优先清除内存(无论如何这是一个caching的angular落效用函数。)BUY RAM你将使用caching,RAM很便宜)。
在这四个选项中,这是我的首选。 我已经实现了这个基本的caching解决scheme。 到目前为止,它似乎完美的工作,没有已知的错误(请联系我下面的评论或jon-at-jondavis,如果有的话),我打算将它用在我所有需要的小项目基本caching。 这里是:
Github链接: https : //github.com/kroimon/ExpirableItemDictionary
旧链接: ExpirableItemDictionary.zip
值得一提的是:AppFabric,NoSQL,Et Al
请注意,这篇博客文章的标题是“简单caching”,而不是“重型caching”。 如果你想进入重型的东西,你应该看看专门的,横向的解决scheme。
MemoryCache就是它所说的,一个caching存储在内存中
HttpRuntime.Cache(请参阅http://msdn.microsoft.com/en-us/library/system.web.httpruntime.cache(v=vs.100).aspx和http://msdn.microsoft.com/en- us / library / system.web.caching.cache.aspx )会保留在您的应用程序中configuration的任何内容。
请参阅例如“ASP.NET 4.0:编写自定义输出caching提供程序” http://weblogs.asp.net/gunnarpeipman/archive/2009/11/19/asp-net-4-0-writing-custom-output-cache -providers.aspx