Tell me more ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

Can't seem to find one, so trying to build a very simple but fast implementation. Thought I would post on SO for review/feedback, and so that others can just copy/paste for their own use.

I'm using a Dictionary and LinkedList, with a non-granular lock. Basic benchmark included below:

public class LRUDictionary<TKey,TValue> : IDictionary<TKey,TValue>
{
    private Dictionary<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>>_dict= 
        new Dictionary<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>>();

    private LinkedList<KeyValuePair<TKey, TValue>> _list = 
        new LinkedList<KeyValuePair<TKey, TValue>>();

    public int Max_Size { get; set; }

    public LRUDictionary(int maxsize)
    {
        Max_Size = maxsize;
    }

    public void Add(TKey key, TValue value)
    {
        lock (_dict)
        {
            LinkedListNode<KeyValuePair<TKey, TValue>> node;

            if (_dict.TryGetValue(key, out node))
            {
                _list.Remove(node);
                _list.AddFirst(node);
            }
            else
            {
                node = new LinkedListNode<KeyValuePair<TKey, TValue>>(
                new KeyValuePair<TKey, TValue>(key, value));

                 _dict.Add(key, node);
                _list.AddFirst(node);

            }

            if (_dict.Count > Max_Size)
            {
                var nodetoremove = _list.Last;
                if (nodetoremove != null)
                    Remove(nodetoremove.Value.Key);
            }
        }

    }

    public bool Remove(TKey key)
    {
        lock (_dict)
        {
            LinkedListNode<KeyValuePair<TKey, TValue>> removednode;
            if (_dict.TryGetValue(key, out removednode))
            {
                _dict.Remove(key);
                _list.Remove(removednode);
                return true;
            }

            else
                return false;
        }
    }

    public bool TryGetValue(TKey key, out TValue value)
    {
        LinkedListNode<KeyValuePair<TKey, TValue>> node;

        bool result = false;
        lock (_dict)
            result = _dict.TryGetValue(key, out node);

        if (node != null)
            value = node.Value.Value;
        else
            value = default(TValue);

        return result;
    }

  [rest of IDictionary not implemented yet]

  }

Benchmark:

class Program
{
    static Random rand = new Random();
    static void Main(string[] args)
    {
        var lruspace = 50;
        var setsize = 100;
        var iterations = 1000 * 1000;
        var lrucache = new LRUDictionary<int, int>(lruspace);
        var watch = new Stopwatch();

        watch.Start();

        Parallel.For(0, iterations, (i) =>
        {
            lrucache.Add(rand.Next(setsize), 0);
            lrucache.Add(rand.Next(setsize), 0);

            lrucache.Remove(rand.Next(setsize));
            lrucache.Add(rand.Next(setsize), 0);

            lrucache.Remove(rand.Next(setsize));
            lrucache.Remove(rand.Next(setsize));

            lrucache.Add(rand.Next(setsize), 0);
            lrucache.Remove(rand.Next(setsize));
            lrucache.Add(rand.Next(setsize), 0);
            lrucache.Add(rand.Next(setsize), 0);
            lrucache.Add(rand.Next(setsize), 0);
        });

        Console.WriteLine(watch.ElapsedMilliseconds);
        Console.ReadLine();

    }
}

Output:

2592ms

Is this the best way to go? Any obvious improvements?

share|improve this question
You might want to take a look at C5 which is available on its Github repo where you can see its source – Dharun Oct 6 '12 at 16:14
your lock sections are too big, also if the thread count goes up, two threads can enter lock at the same time. which breaks your correctness. – DarthVader Oct 6 '12 at 16:18
before you look at performance, look at correctness. i doubt for several threads you will have correct results – DarthVader Oct 6 '12 at 16:19
I'm starting with big locks to ensure correctness. How can two threads enter the lock? – Harry Mexican Oct 6 '12 at 16:21
This one from Lucene.Net is pretty neat. svn.apache.org/repos/asf/lucene.net/trunk/src/core/Util/Cache It is not threadsafe by default, but once you instanciated it, simply call GetSynchronizedCache() to get a ThreadSafe wrapper of it. – Jf Beaulac Oct 6 '12 at 16:39
show 1 more comment

migrated from stackoverflow.com Oct 8 '12 at 15:06

1 Answer

up vote 1 down vote accepted

I found three .NET implementations with a quick Googling:

share|improve this answer
Thanks! IF I had spotted the first one, I would not have bothered, although none of them seem to implement IDictionary. Might do a comparative benchmark, but they seem to all use more or less the same strategy. – Harry Mexican Oct 10 '12 at 9:48

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.