LFU cache in C #?

Is there any ready-made LFU cache in C #?

+4
c # caching
source share
5 answers

I am sure there are others.

Here is the basic LFU implementation with aging for C # that I just hit, itโ€™s not perfect, but it is a good starting point: Note: this implementation is not thread safe.

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace LFU { class LFUCache<TKey,TValue> { Dictionary<TKey, LinkedListNode<CacheNode>> cache = new Dictionary<TKey, LinkedListNode<CacheNode>>(); LinkedList<CacheNode> lfuList = new LinkedList<CacheNode>(); class CacheNode { public TKey Key { get; set; } public TValue Data { get; set; } public int UseCount { get; set; } } int size; int age = 0; int agePolicy; public LFUCache(int size) : this(size, 1000) { } /// <summary> /// /// </summary> /// <param name="size"></param> /// <param name="agePolicy">after this number of gets the cache will take 1 off all UseCounts, forcing old stuff to expire.</param> public LFUCache(int size, int agePolicy) { this.agePolicy = 1000; this.size = size; } public void Add(TKey key, TValue val) { TValue existing; if (!TryGet(key, out existing)) { var node = new CacheNode() {Key = key, Data = val, UseCount = 1}; if (lfuList.Count == size) { cache.Remove(lfuList.First.Value.Key); lfuList.RemoveFirst(); } var insertionPoint = Nodes.LastOrDefault(n => n.Value.UseCount < 2); LinkedListNode<CacheNode> inserted; if (insertionPoint == null) { inserted = lfuList.AddFirst(node); } else { inserted = lfuList.AddAfter(insertionPoint, node); } cache[key] = inserted; } } IEnumerable<LinkedListNode<CacheNode>> Nodes { get { var node = lfuList.First; while (node != null) { yield return node; node = node.Next; } } } IEnumerable<LinkedListNode<CacheNode>> IterateFrom(LinkedListNode<CacheNode> node) { while (node != null) { yield return node; node = node.Next; } } public TValue GetOrDefault(TKey key) { TValue val; TryGet(key, out val); return val; } public bool TryGet(TKey key, out TValue val) { age++; if (age > agePolicy) { age = 0; foreach (var node in cache.Values) { var v = node.Value; v.UseCount--; } } LinkedListNode<CacheNode> data; bool success = false; if (cache.TryGetValue(key, out data)) { var cacheNode = data.Value; val = cacheNode.Data; cacheNode.UseCount++; var insertionPoint = IterateFrom(data).Last(n => n.Value.UseCount <= cacheNode.UseCount); if (insertionPoint != data) { lfuList.Remove(data); lfuList.AddAfter(insertionPoint, data); } } else { val = default(TValue); } return success; } } class Program { public static void Assert(bool condition, string message) { if (!condition) { Console.WriteLine("Assert failed : " + message); throw new ApplicationException("Test Failed"); } } public static void RunAllTests(Program prog){ foreach (var method in prog.GetType().GetMethods()) { if (method.Name.StartsWith("Test")) { try { method.Invoke(prog, null); Console.WriteLine("Test Passed: " + method.Name); } catch (Exception) { Console.WriteLine("Test Failed : " + method.Name); } } } } public void TestItemShouldBeThereOnceInserted() { var cache = new LFUCache<string, int>(3); cache.Add("a", 1); cache.Add("b", 2); cache.Add("c", 3); cache.Add("d", 4); Assert(cache.GetOrDefault("a") == 0, "should get 0"); Assert(cache.GetOrDefault("b") == 2, "should get 2"); Assert(cache.GetOrDefault("c") == 3, "should get 3"); Assert(cache.GetOrDefault("d") == 4, "should get 4"); } public void TestLFUShouldWorkAsExpected() { var cache = new LFUCache<string, int>(3); cache.Add("a", 1); cache.Add("b", 2); cache.Add("c", 3); cache.GetOrDefault("a"); cache.GetOrDefault("a"); cache.GetOrDefault("b"); cache.Add("d", 4); cache.Add("e", 5); Assert(cache.GetOrDefault("a") == 1, "should get 1"); Assert(cache.GetOrDefault("b") == 2, "should get 0"); Assert(cache.GetOrDefault("c") == 0, "should get 0"); Assert(cache.GetOrDefault("d") == 0, "should get 4"); Assert(cache.GetOrDefault("e") == 5, "should get 5"); } static void Main(string[] args) { RunAllTests(new Program()); Console.ReadKey(); } } } 
+7
source share

Such a set does not exist within .NET 3.5. Ayende created a Least Recent Used set. This may be a good start ( code ).

+5
source share

You can check out MS "Velocity" . I'm not sure what strategic strategies they offer, but maybe worth a look. In addition, you can expand the strategies offered by Application Block Caching .

0
source share

I created a mine, FWIW:

https://github.com/ysharplanguage/GenericMemoryCache

(it supports not only LFU, but also LRU / MRU and expands compared to other eviction and replacement policies, if desired)

'Hope this helps,

0
source share

Try CacheCrow , this is a simple LFU, time cache.

0
source share

All Articles