UPDATE: Hey ragazzi, grazie per le risposte. Ieri sera e stasera ho provato alcuni approcci diversi e ne ho trovato uno simile a quello presentato di seguito da Jeff (avevo già fatto ciò che mi aveva suggerito nel suo aggiornamento, e ho messo insieme la mia semplice implementazione LL per ulteriori guadagni). Ecco il codice, a questo punto non sembra più particolarmente pulito, ma sono stato oltre questo molte volte cambiando tutto ciò che potevo per rafforzare le prestazioni.Come posso rendere la mia semplice cache LRU .NET più veloce?
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;
}
ci sono alcune parti che appaiono/sentono traballante - come riutilizzare il vecchio nodo quando si fa un add - ma ero in grado di ottenere una spinta notevole in porformance fuori di essi. Sono stato anche un po 'sorpreso dalla differenza che ha fatto passare da proprietà reali sul nodo a solo variabili pubbliche, ma credo che sia così che va con questa roba. A questo punto il codice di cui sopra è quasi interamente limitato dalle prestazioni delle operazioni del dizionario, quindi non sono sicuro che ne ricaveremo molto di più. Continuerò a pensarci su e ad esaminare alcune delle risposte.
Spiegazione da posta originale: Ciao a tutti. Quindi ho scritto un'implementazione LRU leggera semplice da usare in una libreria di compressione (la sto usando per trovare stringhe di byte corrispondenti nell'input basato su un hash, stile LZW), e sto cercando modi per renderlo più veloce.
Correlati: http://stackoverflow.com/questions/581119/object-cache-for-c –
David, puoi darci un'idea di come utilizzerai la cache? Come sono gli schemi di accesso? Su quanto spesso aggiungi? Quanto spesso ottieni? Quanto spesso fai un "Contiene"? –