C# System.Runtime.Caching.MemoryCache 与 HttpRuntime.Cache - 有什么区别吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13704000/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
System.Runtime.Caching.MemoryCache vs HttpRuntime.Cache - are there any differences?
提问by Giedrius
I'm wondering if there are any differences between MemoryCacheand HttpRuntime.Cache, which one is preferred in ASP.NET MVC projects?
我想知道MemoryCache和之间是否有任何区别HttpRuntime.Cache,ASP.NET MVC 项目中首选哪一个?
As far as I understand, both are thread safe, API is from first sight more or less the same, so is there any difference when to use which?
据我了解,两者都是线程安全的,API乍一看或多或少相同,那么何时使用哪个有什么区别?
采纳答案by Sampath
HttpRuntime.Cachegets the Cachefor the current application.
HttpRuntime.Cache获取Cache当前应用程序的 。
The MemoryCacheclass is similar to the ASP.NET Cacheclass.
该MemoryCache班是类似于ASP.NETCache类。
The MemoryCacheclass has many properties and methods for accessing the cache that will be familiar to you if you have used the ASP.NET Cacheclass.
该MemoryCache班有许多属性和访问缓存,如果你已经使用了ASP.NET,这将是你熟悉的方法Cache类。
The main difference between HttpRuntime.Cacheand MemoryCacheis that the latter has been changed to make it usable by .NET Framework applications that are not ASP.NET applications.
HttpRuntime.Cache和之间的主要区别在于MemoryCache后者已被更改,以使其可供非 ASP.NET 应用程序的 .NET Framework 应用程序使用。
For additional reading:
补充阅读:
Update :
更新 :
According to the users feedback, sometimes Jon davis blog is not working.Hence I have put the whole article as an image.Please see that.
根据用户反馈,有时Jon davis 的博客无法正常工作。因此我将整篇文章作为图片。请参阅。
Note :If it's not clear then just click on the image.After that it'll open on a browser.Then click again on it to zoom :)
注意:如果不清楚,则只需单击图像。之后它将在浏览器上打开。然后再次单击以进行缩放:)
回答by Christian Westman
MemoryCache is what it says it is, a cache stored in memory
MemoryCache 就是它所说的,存储在内存中的缓存
HttpRuntime.Cache (see http://msdn.microsoft.com/en-us/library/system.web.httpruntime.cache(v=vs.100).aspxand http://msdn.microsoft.com/en-us/library/system.web.caching.cache.aspx) persists to whatever you configure it to in your application.
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) 持续到您在应用程序中配置的任何内容。
see for example "ASP.NET 4.0: Writing custom output cache providers" http://weblogs.asp.net/gunnarpeipman/archive/2009/11/19/asp-net-4-0-writing-custom-output-cache-providers.aspx
参见例如“ASP.NET 4.0:编写自定义输出缓存提供程序” http://weblogs.asp.net/gunnarpeipman/archive/2009/11/19/asp-net-4-0-writing-custom-output-cache -providers.aspx
回答by DeepSpace101
Here is Jon Davis' article. To preserve readability, I'm cutting out the now obsolete EntLib section, the intro as well as the conclusion.
这是乔恩戴维斯的文章。为了保持可读性,我删掉了现在已经过时的 EntLib 部分、介绍和结论。
ASP.NET Cache
ASP.NET 缓存
ASP.NET, or the System.Web.dll assembly, does have a caching mechanism. It was never intended to be used outside of a web context, but it can be used outside of the web, and it does perform all of the above expiration behaviors in a hashtable of sorts.
ASP.NET 或 System.Web.dll 程序集确实具有缓存机制。它从未打算在 Web 上下文之外使用,但它可以在 Web 之外使用,并且它确实在各种哈希表中执行所有上述过期行为。
After scouring Google, it appears that quite a few people who have discussed the built-in caching functionality in .NET have resorted to using the ASP.NET cache in their non-web projects. This is no longer the most-available, most-supported built-in caching system in .NET; .NET 4 has an ObjectCache which I'll get into later. Microsoft has always been adamant that the ASP.NET cache is not intended for use outside of the web. But many people are still stuck in .NET 2.0 and .NET 3.5, and need something to work with, and this happens to work for many people, even though MSDN says clearly:
在谷歌搜索之后,似乎有不少讨论过 .NET 中内置缓存功能的人在他们的非 Web 项目中求助于使用 ASP.NET 缓存。这不再是 .NET 中最可用、最受支持的内置缓存系统;.NET 4 有一个 ObjectCache,我稍后会介绍。Microsoft 一直坚持认为 ASP.NET 缓存不适合在 Web 之外使用。但是很多人仍然停留在 .NET 2.0 和 .NET 3.5 中,需要一些东西来工作,而这恰好适用于很多人,尽管 MSDN 明确说:
Note: The Cache class is not intended for use outside of ASP.NET applications. It was designed and tested for use in ASP.NET to provide caching for Web applications. In other types of applications, such as console applications or Windows Forms applications, ASP.NET caching might not work correctly.
注意:Cache 类不适合在 ASP.NET 应用程序之外使用。它被设计和测试用于在 ASP.NET 中为 Web 应用程序提供缓存。在其他类型的应用程序(例如控制台应用程序或 Windows 窗体应用程序)中,ASP.NET 缓存可能无法正常工作。
The class for the ASP.NET cache is System.Web.Caching.Cache in System.Web.dll. However, you cannot simply new-up a Cache object. You must acquire it from System.Web.HttpRuntime.Cache.
ASP.NET 缓存的类是 System.Web.Caching.Cache 中的 System.Web.dll。但是,您不能简单地新建一个 Cache 对象。您必须从 System.Web.HttpRuntime.Cache 获取它。
Cache cache = System.Web.HttpRuntime.Cache;
Working with the ASP.NET cache is documented on MSDN here.
使用 ASP.NET 缓存记录在 MSDN此处。
Pros:
优点:
- It's built-in.
- Despite the .NET 1.0 syntax, it's fairly simpleto use.
- When used in a web context, it's well-tested. Outside of web contexts, according to Google searches it is not commonly known to cause problems, despite Microsoft recommending against it, so long as you're using .NET 2.0 or later.
- You can be notifiedvia a delegate when an item is removed, which is necessary if you need to keep it alive and you could not set the item's priority in advance.
- Individual items have the flexibilityof any of (a), (b), or (c) methods of expiration and removal in the list of removal methods at the top of this article. You can also associate expiration behavior with the presence of a physical file.
- 它是内置的。
- 尽管使用 .NET 1.0 语法,但使用起来相当简单。
- 在 Web 上下文中使用时,它已经过充分测试。在 Web 上下文之外,根据 Google 搜索,它通常不会引起问题,尽管 Microsoft 不建议这样做,只要您使用 .NET 2.0 或更高版本。
- 当一个项目被移除时,你可以通过代理收到通知,如果你需要让它保持活动状态并且你不能提前设置项目的优先级,这是必要的。
- 在本文顶部的移除方法列表中,个别物品具有(a)、(b) 或 (c) 任何一种过期和移除方法的灵活性。您还可以将过期行为与物理文件的存在相关联。
Cons:
缺点:
- Not only is it static, there is only one. You cannot create your own type with its own static instance of a Cache. You can only have one bucket for your entire app, period. You can wrap the bucket with your own wrappers that do things like pre-inject prefixes in the keys and remove these prefixes when you pull the key/value pairs back out. But there is still only one bucket. Everything is lumped together. This can be a real nuisance if, for example, you have a service that needs to cache three or four different kinds of data separately. This shouldn't be a big problem for pathetically simple projects. But if a project has any significant degree of complexity due to its requirements, the ASP.NET cache will typically not suffice.
- Items can disappear, willy-nilly. A lot of people aren't aware of this—I wasn't, until I refreshed my knowledge on this cache implementation. By default, the ASP.NET cache is designed to destroy items when it “feels” like it. More specifically, see (c) in my definition of a cache table at the top of this article. If another thread in the same process is working on something completely different, and it dumps high-priority items into the cache, then as soon as .NET decides it needs to require some memory it will start to destroy some items in the cache according to their priorities, lower priorities first. All of the examples documented here for adding cache items use the default priority, rather than the NotRemovable priority value which keeps it from being removed for memory-clearing purposes but will still remove it according to the expiration policy. Peppering CacheItemPriority.NotRemovable in cache invocations can be cumbersome, otherwise a wrapper is necessary.
- The key must be a string.If, for example, you are caching data records where the records are keyed on a long or an integer, you must convert the key to a string first.
- The syntax is stale. It's .NET 1.0 syntax, even uglier than ArrayList or Hashtable. There are no generics here, no IDictionary<> interface. It has no Contains() method, no Keys collection, no standard events; it only has a Get() method plus an indexer that does the same thing as Get(), returning null if there is no match, plus Add(), Insert() (redundant?), Remove(), and GetEnumerator().
- Ignores the DRY principleof setting up your default expiration/removal behaviors so you can forget about them. You have to explicitly tell the cache how you want the item you're adding to expire or be removed every time you add add an item.
- No way to access the caching detailsof a cached item such as the timestamp of when it was added. Encapsulation went a bit overboard here, making it difficult to use the cache when in code you're attempting to determine whether a cached item should be invalidated against another caching mechanism (i.e. session collection) or not.
- Removal eventsare not exposed as events and must be tracked at the time of add.
- And if I haven't said it enough, Microsoft explicitly recommends against itoutside of the web. And if you're cursed with .NET 1.1, you not supposed to use it with any confidence of stability at alloutside of the web so don't bother.
- 它不仅是静态的,而且只有一个. 您不能使用自己的静态缓存实例创建自己的类型。您的整个应用程序只能有一个存储桶,期间。您可以使用自己的包装器包装存储桶,这些包装器可以在键中预先注入前缀,并在您将键/值对拉回时删除这些前缀。但仍然只有一个桶。一切都混为一谈。例如,如果您的服务需要分别缓存三种或四种不同类型的数据,这可能会很麻烦。对于可悲的简单项目来说,这应该不是什么大问题。但是,如果项目由于其要求而具有任何显着程度的复杂性,则 ASP.NET 缓存通常是不够的。
- 物品可能会消失,不管怎样. 很多人都没有意识到这一点——我没有意识到,直到我重新了解了这个缓存实现。默认情况下,ASP.NET 缓存旨在在它“感觉”喜欢它时销毁项目。更具体地说,请参阅本文顶部我对缓存表的定义中的 (c)。如果同一进程中的另一个线程正在处理完全不同的事情,并且它将高优先级项目转储到缓存中,那么一旦 .NET 决定需要一些内存,它就会根据以下内容开始销毁缓存中的一些项目他们的优先级,较低的优先级。此处记录的所有用于添加缓存项的示例都使用默认优先级,而不是 NotRemovable 优先级值,这可以防止出于内存清除目的而将其删除,但仍会根据到期策略将其删除。
- 键必须是字符串。例如,如果您正在缓存以 long 或 integer 为键的数据记录,则必须先将键转换为字符串。
- 语法陈旧。它是 .NET 1.0 语法,甚至比 ArrayList 或 Hashtable 还要丑陋。这里没有泛型,没有 IDictionary<> 接口。它没有Contains()方法,没有Keys集合,没有标准事件;它只有一个 Get() 方法加上一个与 Get() 做同样事情的索引器,如果没有匹配则返回 null,加上 Add()、Insert()(冗余?)、Remove() 和 GetEnumerator() .
- 忽略设置默认过期/删除行为的 DRY 原则,以便您可以忘记它们。您必须明确告诉缓存您希望每次添加的项目如何过期或被删除。
- 无法访问缓存项的缓存详细信息,例如添加时的时间戳。封装在这里有点过火,当您在代码中尝试确定缓存项是否应针对另一种缓存机制(即会话集合)失效时,很难使用缓存。
- 删除事件不会作为事件公开,必须在添加时进行跟踪。
- 如果我说得还不够多,微软明确建议不要在网络之外使用它。如果您被.NET 1.1诅咒,那么您不应该在网络之外完全放心地使用它,所以不要打扰。
.NET 4.0's ObjectCache / MemoryCache
.NET 4.0 的 ObjectCache / MemoryCache
Microsoft finally implemented an abstract ObjectCache class in the latest version of the .NET Framework, and a MemoryCache implementation that inherits and implements ObjectCache for in-memory purposes in a non-web setting.
Microsoft 最终在最新版本的 .NET Framework 中实现了一个抽象的 ObjectCache 类,以及一个 MemoryCache 实现,该实现继承并实现了 ObjectCache,用于非 Web 设置中的内存中目的。
System.Runtime.Caching.ObjectCache is in the System.Runtime.Caching.dll assembly. It is an abstract class that that declares basically the same .NET 1.0 style interfaces that are found in the ASP.NET cache. System.Runtime.Caching.MemoryCacheis the in-memory implementation of ObjectCache and is very similar to the ASP.NET cache, with a few changes.
System.Runtime.Caching.ObjectCache 位于 System.Runtime.Caching.dll 程序集中。它是一个抽象类,它声明的 .NET 1.0 样式接口与 ASP.NET 缓存中的接口基本相同。System.Runtime.Caching.MemoryCache是 ObjectCache 的内存中实现,与 ASP.NET 缓存非常相似,但有一些变化。
To add an item with a sliding expiration, your code would look something like this:
要添加具有滑动到期时间的项目,您的代码将如下所示:
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)
});
Pros:
优点:
- It's built-in, and now supported and recommended by Microsoft outside of the web.
Unlike the ASP.NET cache, you can instantiate a MemoryCache object instance.
Note: It doesn't have to be static, but it should be—that is Microsoft's recommendation (see yellow Caution).
A few slight improvements have been made vs. the ASP.NET cache's interface, such as the ability to subscribe to removal events without necessarily being there when the items were added, the redundant Insert() was removed, items can be added with a CacheItem object with an initializer that defines the caching strategy, and Contains() was added.
- 它是内置的,现在在 Web 之外得到 Microsoft 的支持和推荐。
与 ASP.NET 缓存不同,您可以实例化 MemoryCache 对象实例。
注意:它不必是静态的,但它应该是——这是Microsoft 的建议(参见黄色警告)。
相对于 ASP.NET 缓存的接口进行了一些细微的改进,例如订阅删除事件的能力,而不必在添加项目时就在那里,删除了冗余的 Insert(),可以使用 CacheItem 添加项目带有定义缓存策略的初始化程序的对象,并添加了 Contains()。
Cons:
缺点:
- Still does not fully reinforce DRY. From my small amount of experience, you still can't set the sliding expiration TimeSpan once and forget about it. And frankly, although the policy in the item-add sample above is more readable, it necessitates horrific verbosity.
- It is still not generically-keyed; it requires a string as the key. So you can't store as long or int if you're caching data records, unless you convert to string.
- 仍然没有完全强化 DRY。以我的少量经验,你还是不能设置一次滑动过期TimeSpan就忘记了。坦率地说,虽然上面的 item-add 示例中的策略更具可读性,但它需要可怕的冗长。
- 它仍然不是通用键控;它需要一个字符串作为键。因此,如果您正在缓存数据记录,则无法存储 long 或 int,除非您转换为字符串。
DIY: Build One Yourself
DIY:自己建造一个
It's actually pretty simple to create a caching dictionary that performs explicit or sliding expiration. (It gets a lot harder if you want items to be auto-removed for memory-clearing purposes.) Here's all you have to do:
创建一个执行显式或滑动过期的缓存字典实际上非常简单。(如果您希望出于清除内存的目的而自动删除项目,这会变得更加困难。)以下是您需要做的所有事情:
- Create a value container class called something like Expiring or Expirable that would contain a value of type T, a TimeStamp property of type DateTime to store when the value was added to the cache, and a TimeSpan that would indicate how far out from the timestamp that the item should expire. For explicit expiration you can just expose a property setter that sets the TimeSpan given a date subtracted by the timestamp.
- Create a class, let's call it ExpirableItemsDictionary, that implements IDictionary. I prefer to make it a generic class with defined by the consumer.
- In the the class created in #2, add a Dictionary> as a property and call it InnerDictionary.
- The implementation if IDictionary in the class created in #2 should use the InnerDictionary to store cached items. Encapsulation would hide the caching method details via instances of the type created in #1 above.
- Make sure the indexer (this[]), ContainsKey(), etc., are careful to clear out expired items and remove the expired items before returning a value. Return null in getters if the item was removed.
- Use thread locks on all getters, setters, ContainsKey(), and particularly when clearing the expired items.
- Raise an event whenever an item gets removed due to expiration.
- Add a System.Threading.Timer instance and rig it during initialization to auto-remove expired items every 15 seconds. This is the same behavior as the ASP.NET cache.
- You may want to add an AddOrUpdate() routine that pushes out the sliding expiration by replacing the timestamp on the item's container (Expiring instance) if it already exists.
- 创建一个名为 Expiring 或 Expirable 之类的值容器类,该类将包含 T 类型的值、DateTime 类型的 TimeStamp 属性以存储该值何时添加到缓存中,以及一个 TimeSpan 指示距时间戳有多远该项目应该过期。对于显式到期,您可以只公开一个属性设置器,该设置器设置给定日期减去时间戳的时间跨度。
- 创建一个类,我们称之为 ExpirableItemsDictionary,它实现了 IDictionary。我更喜欢把它变成一个由消费者定义的泛型类。
- 在#2 中创建的类中,添加一个 Dictionary> 作为属性并将其命名为 InnerDictionary。
- #2 中创建的类中的 if IDictionary 实现应该使用 InnerDictionary 来存储缓存项。封装将通过上面#1 中创建的类型的实例隐藏缓存方法的详细信息。
- 确保索引器 (this[])、ContainsKey() 等在返回值之前小心地清除过期项目并删除过期项目。如果删除了项目,则在 getter 中返回 null。
- 对所有 getter、setter、ContainsKey() 使用线程锁,尤其是在清除过期项目时。
- 每当项目因过期而被删除时引发事件。
- 添加 System.Threading.Timer 实例并在初始化期间对其进行装配,以每 15 秒自动删除过期项目。这与 ASP.NET 缓存的行为相同。
- 您可能想要添加一个 AddOrUpdate() 例程,通过替换项目容器(过期实例)上的时间戳(如果它已经存在)来推出滑动过期。
Microsoft has to support its original designs because its user base has built up a dependency upon them, but that does not mean that they are good designs.
微软必须支持它的原始设计,因为它的用户群已经建立了对它们的依赖,但这并不意味着它们是好的设计。
Pros:
优点:
- You have complete controlover the implementation.
- Can reinforce DRYby setting up default caching behaviors and then just dropping key/value pairs in without declaring the caching details each time you add an item.
- Can implement modern interfaces, namely
IDictionary<K,T>. This makes it much easier to consume as its interface is more predictable as a dictionary interface, plus it makes it more accessible to helpers and extension methods that work with IDictionary<>. - Caching details can be unencapsulated, such as by exposing your InnerDictionary via a public read-only property, allowing you to write explicit unit tests against your caching strategy as well as extend your basic caching implementation with additional caching strategies that build upon it.
- Although it is not necessarily a familiar interface for those who already made themselves comfortable with the .NET 1.0 style syntax of the ASP.NET cache or the Caching Application Block, you can define the interfaceto look like however you want it to look.
- Can use any type for keys. This is one reason why generics were created. Not everything should be keyed with a string.
- 您可以完全控制实施。
- 可以通过设置默认缓存行为来加强 DRY,然后在每次添加项目时只删除键/值对,而无需声明缓存详细信息。
- 可以实现现代接口,即
IDictionary<K,T>. 这使得它更容易使用,因为它的接口作为字典接口更容易预测,而且它使与 IDictionary<> 一起工作的助手和扩展方法更容易访问。 - 缓存细节可以是未封装的,例如通过公共只读属性公开 InnerDictionary,允许您针对缓存策略编写显式单元测试,并使用基于它的附加缓存策略扩展基本缓存实现。
- 尽管对于那些已经熟悉 ASP.NET 缓存或缓存应用程序块的 .NET 1.0 样式语法的人来说,它不一定是一个熟悉的界面,但您可以将界面定义为您想要的样子。
- 可以使用任何类型的键。这是创建泛型的原因之一。不是所有的东西都应该用一个字符串作为键。
Cons:
缺点:
- Is not invented by, nor endorsed by, Microsoft, so it is not going to have the same quality assurance.
- Assuming only the instructions I described above are implemented, does not “willy-nilly” clear items for clearing memory on a priority basis (which is a corner-case utility function of a cache anyway .. BUY RAM where you would be using the cache, RAM is cheap).
- 不是由 Microsoft 发明的,也不是由 Microsoft 认可的,因此不会有相同的质量保证。
- 假设只实现了我上面描述的指令,不会“无意识地”清除项目以优先清除内存(无论如何,这是缓存的一个特殊实用功能.. 购买将使用缓存的 RAM ,RAM 很便宜)。
Among all four of these options, this is my preference. I have implemented this basic caching solution. So far, it seems to work perfectly, there are no known bugs (please contact me with comments below or at jon-at-jondavis if there are!!), and I intend to use it in all of my smaller side projects that need basic caching. Here it is:
在这四个选项中,这是我的偏好。我已经实现了这个基本的缓存解决方案。到目前为止,它似乎工作得很好,没有已知的错误(请通过下面的评论或在 jon-at-jondavis 与我联系,如果有的话!!),我打算在我所有需要的较小的副项目中使用它基本缓存。这里是:
Github link: https://github.com/kroimon/ExpirableItemDictionary
Github 链接:https: //github.com/kroimon/ExpirableItemDictionary
Old Link: ExpirableItemDictionary.zip
旧链接:ExpirableItemDictionary.zip
Worthy Of Mention: AppFabric, NoSQL, Et Al
值得一提:AppFabric、NoSQL、等
Notice that the title of this blog article indicates “Simple Caching”, not “Heavy-Duty Caching”. If you want to get into the heavy-duty stuff, you should look at dedicated, scale out solutions.
请注意,这篇博客文章的标题表示“简单缓存”,而不是“重载缓存”。如果您想进入繁重的工作,您应该查看专用的横向扩展解决方案。
回答by Alex
MemoryCache.Default can also serve as a "bridge" if you're migrating a classic ASP.NET MVC app to ASP.NET Core, because there's no "System.Web.Caching" and "HttpRuntime" in Core.
如果您要将经典的 ASP.NET MVC 应用程序迁移到 ASP.NET Core,MemoryCache.Default 也可以充当“桥梁”,因为 Core 中没有“System.Web.Caching”和“HttpRuntime”。
I also wrote a small benchmark to store a boolitem 20000 times (and another benchmark to retrieve it) and MemoryCache seems to be two times slower(27ms vs 13ms - that's total for all 20k iterations) but they're both super-fast and this can probably be ignored.
我还写了一个小的基准来存储一个bool项目 20000 次(和另一个基准来检索它)并且 MemoryCache 似乎慢了两倍(27ms vs 13ms - 这是所有 20k 迭代的总和)但是它们都超级快,这个大概可以忽略。


