UPDATE: Hey Leute, danke für die Antworten. Letzte Nacht und heute Abend habe ich ein paar verschiedene Ansätze ausprobiert und eine ähnliche wie die von Jeff (ich hatte sogar schon gemacht, was er in seinem Update vorgeschlagen hatte) entwickelt und meine eigene einfache LL-Implementierung für zusätzliche Gewinne zusammengestellt. Hier ist der Code, an diesem Punkt sieht es nicht mehr besonders sauber aus, aber ich habe unzählige Male daran gearbeitet, alles zu ändern, was ich konnte, um die Leistung zu steigern.Wie kann ich meinen einfachen .NET-LRU-Cache schneller machen?
public class NewLRU2<K, V> where V : class
{
int m_iMaxItems;
Dictionary<K, LRUNode<K, V>> m_oMainDict;
private LRUNode<K,V> m_oHead;
private LRUNode<K,V> m_oTail;
private LRUNode<K,V> m_oCurrent;
public NewLRU2(int iSize)
{
m_iMaxItems = iSize;
m_oMainDict = new Dictionary<K, LRUNode<K,V>>();
m_oHead = null;
m_oTail = null;
}
public V this[K key]
{
get
{
m_oCurrent = m_oMainDict[key];
if (m_oCurrent == m_oHead)
{
//do nothing
}
else if (m_oCurrent == m_oTail)
{
m_oTail = m_oCurrent.Next;
m_oTail.Prev = null;
m_oHead.Next = m_oCurrent;
m_oCurrent.Prev = m_oHead;
m_oCurrent.Next = null;
m_oHead = m_oCurrent;
}
else
{
m_oCurrent.Prev.Next = m_oCurrent.Next;
m_oCurrent.Next.Prev = m_oCurrent.Prev;
m_oHead.Next = m_oCurrent;
m_oCurrent.Prev = m_oHead;
m_oCurrent.Next = null;
m_oHead = m_oCurrent;
}
return m_oCurrent.Value;
}
}
public void Add(K key, V value)
{
if (m_oMainDict.Count >= m_iMaxItems)
{
//remove old
m_oMainDict.Remove(m_oTail.Key);
//reuse old
LRUNode<K, V> oNewNode = m_oTail;
oNewNode.Key = key;
oNewNode.Value = value;
m_oTail = m_oTail.Next;
m_oTail.Prev = null;
//add new
m_oHead.Next = oNewNode;
oNewNode.Prev = m_oHead;
oNewNode.Next = null;
m_oHead = oNewNode;
m_oMainDict.Add(key, oNewNode);
}
else
{
LRUNode<K, V> oNewNode = new LRUNode<K, V>(key, value);
if (m_oHead == null)
{
m_oHead = oNewNode;
m_oTail = oNewNode;
}
else
{
m_oHead.Next = oNewNode;
oNewNode.Prev = m_oHead;
m_oHead = oNewNode;
}
m_oMainDict.Add(key, oNewNode);
}
}
public bool Contains(K key)
{
return m_oMainDict.ContainsKey(key);
}
}
internal class LRUNode<K,V>
{
public LRUNode(K key, V val)
{
Key = key;
Value = val;
}
public K Key;
public V Value;
public LRUNode<K, V> Next;
public LRUNode<K, V> Prev;
}
Es gibt ein paar Teile, die aussehen/fühlen wackelig - wie der alte Knoten wiederverwendet, wenn ein Add tun - aber ich konnte eine spürbare Steigerung der porformance aus ihnen heraus bekommen. Ich war auch etwas überrascht über den Unterschied, den es gemacht hat, von den tatsächlichen Eigenschaften auf dem Knoten zu nur öffentlichen Variablen zu wechseln, aber ich denke, so geht es mit diesem Zeug. An dieser Stelle ist der obige Code fast ausschließlich durch die Wörterbuchoperationen performancebegrenzt, so dass ich nicht sicher bin, ob ich viel mehr davon rausholen könnte. Ich werde weiter darüber nachdenken und mir einige der Antworten ansehen.
Erklärung Vom ursprünglichen Beitrag: Hallo alle. Also habe ich eine einfache leichte LRU-Implementierung für den Einsatz in einer Komprimierungsbibliothek geschrieben (ich benutze es, um passende Byte-Strings in der Eingabe basierend auf einem Hash, LZW-Stil zu finden), und ich suche nach Möglichkeiten mach es schneller.
Verbunden: http://StackOverflow.com/Questions/581119/Object-Cache-for-C –
David, können Sie uns eine Vorstellung davon geben, wie Sie den Cache verwenden werden? Wie sehen die Zugriffsmuster aus? Wie oft fügst du hinzu? Wie oft bekommst du? Wie oft machst du ein "Enthält"? –