C#:如何实现智能缓存
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1131305/
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
C#: How to implement a smart cache
提问by Svish
I have some places where implementing some sort of cache might be useful. For example in cases of doing resource lookups based on custom strings, finding names of properties using reflection, or to have only one PropertyChangedEventArgs
per property name.
我在某些地方实现某种缓存可能很有用。例如,在基于自定义字符串进行资源查找、使用反射查找属性名称或PropertyChangedEventArgs
每个属性名称只有一个的情况下。
A simple example of the last one:
最后一个的简单例子:
public static class Cache
{
private static Dictionary<string, PropertyChangedEventArgs> cache;
static Cache()
{
cache = new Dictionary<string, PropertyChangedEventArgs>();
}
public static PropertyChangedEventArgs GetPropertyChangedEventArgs(
string propertyName)
{
if (cache.ContainsKey(propertyName))
return cache[propertyName];
return cache[propertyName] = new PropertyChangedEventArgs(propertyName);
}
}
But, will this work well? For example if we had a whole load of different propertyNames, that would mean we would end up with a huge cache sitting there never being garbage collected or anything. I'm imagining if what is cached are larger values and if the application is a long-running one, this might end up as kind of a problem... or what do you think? How should a good cache be implemented? Is this one good enough for most purposes? Any examples of some nice cache implementations that are not too hard to understand or way too complex to implement?
但是,这会奏效吗?例如,如果我们有一大堆不同的 propertyNames,那将意味着我们最终会有一个巨大的缓存坐在那里,永远不会被垃圾收集或任何东西。我想如果缓存的是更大的值,如果应用程序是一个长期运行的应用程序,这可能最终会成为一个问题......或者你怎么看?一个好的缓存应该如何实现?对于大多数用途,这是否足够好?有一些不错的缓存实现的例子,它们不太难理解或实现起来不太复杂?
采纳答案by LukeH
You could wrap each of your cached items in a WeakReference
. This would allow the GC to reclaim items if-and-when required, however it doesn't give you any granular control of when items will disappear from the cache, or allow you to implement explicit expiration policies etc.
您可以将每个缓存的项目包装在WeakReference
. 这将允许 GC 在需要时回收项目,但是它不会让您对项目何时从缓存中消失进行任何精细控制,或者允许您实施明确的过期策略等。
(Ha! I just noticed that the example given on the MSDN pageis a simple caching class.)
(哈!我刚刚注意到MSDN 页面上给出的示例是一个简单的缓存类。)
回答by Fabian Vilers
This is a nice debate to have, but depending your application, here's some tips:
这是一个很好的辩论,但根据您的应用程序,这里有一些提示:
You should define the max size of the cache, what to do with old items if your cache is full, have a scavenging strategy, determine a time to live of the object in the cache, does your cache can/must be persisted somewhere else that memory, in case of application abnormal termination, ...
您应该定义缓存的最大大小,如果缓存已满,如何处理旧项目,制定清理策略,确定缓存中对象的生存时间,您的缓存是否可以/必须保留在其他地方内存,万一应用程序异常终止,...
回答by Adam Luter
This is a large problem, you need to determine the domain of the problem and apply the correct techniques. For instance, how would you describe the expiration of the objects? Do they become stale over a fixed interval of time? Do they become stale from an external event? How frequently does this happen? Additionally, how many objects do you have? Finally, how much does it cost to generate the object?
这是一个大问题,您需要确定问题的领域并应用正确的技术。例如,您将如何描述对象的到期时间?它们是否在固定的时间间隔内变得陈旧?它们是否因外部事件而变得陈旧?这种情况发生的频率如何?另外,你有多少对象?最后,生成对象的成本是多少?
The simplest strategy would be to do straight memoization, as you have above. This assumes that objects never expire, and that there are not so many as to run your memory dry andthat you think the cost to create these objects warrants the use of a cache to begin with.
最简单的策略是直接记忆,如上所述。这假设对象永远不会过期,并且没有太多的内存会耗尽你的内存,并且你认为创建这些对象的成本保证开始使用缓存。
The next layer might be to limit the number of objects, and use an implicit expiration policy, such as LRU (least recently used). To do this you'd typically use a doubly linked list in addition to your dictionary, and every time an objects is accessed it is moved to the front of the list. Then, if you need to add a new object, but it is over your limit of total objects, you'd remove from the back of the list.
下一层可能是限制对象的数量,并使用隐式过期策略,例如 LRU(最近最少使用)。为此,除了字典之外,您通常还使用双向链表,并且每次访问对象时,它都会移动到列表的前面。然后,如果您需要添加一个新对象,但它超出了您的对象总数限制,则应从列表的后面删除。
Next, you might need to enforce explicit expiration, either based on time, or some external stimulus. This would require you to have some sort of expiration event that could be called.
接下来,您可能需要根据时间或某些外部刺激强制执行明确的到期。这将要求您具有某种可以调用的到期事件。
As you can see there is alot of design in caching, so you need to understand your domain and engineer appropriately. You did not provide enough detail for me to discuss specifics, I felt.
正如您所看到的,缓存中有很多设计,因此您需要适当地了解您的领域和工程师。我觉得你没有提供足够的细节让我讨论细节。
P.S. Please consider using Generics when defining your class so that many types of objects can be stored, thus allowing your caching code to be reused.
PS 请在定义类时考虑使用泛型,以便可以存储多种类型的对象,从而允许重用缓存代码。
回答by mfawzymkh
This is a common problem that has many solutions depending on your application need. It is so common that Microsoft released a whole library to address it. You should check out Microsoft Velocity before rolling up your own cache. http://msdn.microsoft.com/en-us/data/cc655792.aspxHope this help.
这是一个常见问题,根据您的应用需求有多种解决方案。微软发布了一个完整的库来解决它是非常普遍的。在汇总自己的缓存之前,您应该先查看 Microsoft Velocity。 http://msdn.microsoft.com/en-us/data/cc655792.aspx希望这会有所帮助。
回答by rob
You could use a WeakReference
but if your object is not that large than don't because the WeakReference
would be taking more memory than the object itself which is not a good technique. Also, if the object is a short-time usage where it will never make it to generation 1 from generation 0 on the GC, there is not much need for the WeakReference
but IDisposable interface on the object would have with the release on SuppressFinalize
.
你可以使用 aWeakReference
但是如果你的对象不是那么大,因为它WeakReference
会比对象本身占用更多的内存,这不是一个好的技术。此外,如果对象是短期使用,它永远不会在 GC 上从第 0 代进入第 1 代,则WeakReference
对象上的但 IDisposable 接口在SuppressFinalize
.
If you want to control the lifetime you need a timer to update the datetime/ timespan again the desiredExpirationTime on the object in your cache.
如果您想控制生命周期,您需要一个计时器来再次更新缓存中对象上的 desiredExpirationTime 日期时间/时间跨度。
The important thing is if the object is large then opt for the WeakReference else use the strong reference. Also, you can set the capacity on the Dictionary and create a queue for requesting additional objects in your temp bin serializing the object and loading it when there is room in the Dictionary, then clear it from the temp directory.
重要的是,如果对象很大,则选择 WeakReference,否则使用强引用。此外,您可以在字典上设置容量并创建一个队列,用于请求临时库中的其他对象序列化对象并在字典中有空间时加载它,然后从临时目录中清除它。
回答by Brendan Byrd
Looks like .NET 4.0 now supports System.Runtime.Caching for caching many types of things. You should look into that first, instead of re-inventing the wheel. More details:
看起来 .NET 4.0 现在支持 System.Runtime.Caching 来缓存多种类型的东西。你应该先研究一下,而不是重新发明轮子。更多细节:
http://msdn.microsoft.com/en-us/library/system.runtime.caching%28VS.100%29.aspx
http://msdn.microsoft.com/en-us/library/system.runtime.caching%28VS.100%29.aspx