ОБНОВЛЕНИЕ: Эй, ребята, спасибо за ответы. Прошлой ночью и сегодня я попробовал несколько разных подходов и придумал один, похожий на тот, который был приведен ниже Джеффом (я даже уже сделал то, что он предложил в его обновлении, и собрал мою собственную простую реализацию LL для дополнительных достижений). Вот код, на данный момент он больше не выглядит чисто чистым, но я уже много раз менял все, что мог, чтобы повысить производительность.Как ускорить мой простой кеш .NET LRU?
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;
}
Есть несколько частей, которые выглядят/чувствовать себя шаткими - как повторное использование старого узла при выполнении надстройки - но я был в состоянии получить заметный импульс в porformance из них. Я также был немного удивлен различием, которое он сделал, чтобы переключиться с фактических свойств узла на просто общедоступные переменные, но я думаю, что так оно и есть. На данный момент код, приведенный выше, почти полностью ограничен операциями словаря, поэтому я не уверен, что получаю намного больше от его затирания. Я буду продолжать думать об этом и изучить некоторые ответы.
Объяснение От оригинала сообщения: Привет всем. Итак, я написал простую облегченную реализацию LRU для использования в библиотеке сжатия (я использую ее для поиска совпадающих байт-строк во входном файле на основе хеша, LZW-стиля), и я ищу способы сделайте это быстрее.
Связанный: http://stackoverflow.com/questions/581119/object-cache-for-c –
Дэвид, можете ли вы дать нам представление о том, как вы будете использовать кеш? Как выглядят шаблоны доступа? О том, как часто вы добавляете? Как часто вы получаете? Как часто вы делаете «Содержит»? –