ACTUALIZACIÓN: Hola chicos gracias por las respuestas. Anoche y esta noche probé algunos enfoques diferentes y obtuve uno similar al que presenta Jeff (ya había hecho lo que sugería en su actualización, y armé mi propia implementación de LL para obtener ganancias adicionales). Aquí está el código, en este punto ya no se ve particularmente limpio, pero he pasado por esto muchas veces cambiando todo lo que pude para mejorar el rendimiento.¿Cómo puedo hacer que mi caché. LRU simple sea más rápido?
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;
}
Hay algunas partes que se ven/sienten poco firme - como la reutilización del nodo de edad cuando se hace un add - pero yo era capaz de conseguir un impulso apreciable en porformance fuera de ellos. También me sorprendió un poco la diferencia que suponía cambiar de propiedades reales en el nodo a solo variables públicas, pero supongo que así es como funciona esto. En este punto, el código anterior está limitado casi por completo por las operaciones del diccionario, por lo que no estoy seguro de que pueda obtener mucho más de lo necesario. Continuaré pensando en ello y veré algunas de las respuestas.
Explicación del mensaje original: Hola a todos. Así que he escrito una implementación de LRU liviana simple para usar en una biblioteca de compresión (la estoy usando para encontrar cadenas de bytes coincidentes en la entrada basada en un hash, estilo LZW), y estoy buscando formas de hazlo mas rapido.
Relacionados: http://stackoverflow.com/questions/581119/object-cache-for-c –
David, ¿nos puede dar una idea de cómo va a utilizar el caché? ¿Cómo son los patrones de acceso? ¿Con qué frecuencia agregas? ¿Con qué frecuencia? ¿Con qué frecuencia haces un "Contiene"? –