La meilleure façon de mettre de cache LRU
J'ai été confronté à ce problème de cache LRU mise en œuvre lorsque, après la taille de la mémoire cache est plein, le moins récemment utilisé le point est sauté et il est remplacé par un nouvel élément.
J'ai deux implémentations à l'esprit:
1). Créer deux cartes qui ressemble à quelque chose comme ceci
std::map<timestamp, k> time_to_key
std::map<key, std::pair<timestamp, V>> LRUCache
Pour insérer un nouvel élément, nous pouvons mettre le timestamp actuel et la valeur dans la LRUCache. Tandis que lorsque la taille du cache est plein, nous pouvons expulser les moins récents élément par trouver le plus petit timestamp présents dans temps_to_clé et le retrait de la clé correspondante de LRUCache.
L'insertion d'un nouvel élément est O(1), mise à jour le timestamp est O(n) (car nous avons besoin de rechercher la k correspondant à l'horodatage dans temps_to_clé.
2). Avoir une liste liée dans lequel la moins récemment utilisée cache est présent à la tête et le nouvel élément est ajouté à la queue. Lors de l'arrivée d'un élément qui est déjà présent dans le cache, le nœud correspondant à la clé de l'élément est déplacé vers la queue de la liste.
L'insertion d'un nouvel élément est O(1), mise à jour le timestamp est de nouveau en O(n) (car nous avons besoin de se déplacer à la queue de la liste), et la suppression d'un élément est O(1).
Maintenant, j'ai les questions suivantes:
- Où l'une de ces implémentations est mieux pour un LRUCache.
- Est-il un autre moyen pour mettre en œuvre la LRU Cache.
- En Java, dois-je utiliser HashMap pour mettre en œuvre les LRUCache
- J'ai vu des questions comme, de mettre en œuvre un générique cache LRU, et ont aussi des questions comme la mise en œuvre d'un cache LRU. Est générique cache LRU différente de cache LRU?
Merci d'avance!!!
EDIT:
D'une autre façon (plus simple) pour mettre en œuvre LRUCache en Java, en utilisant LinkedHashMap et en remplaçant le booléen removeEldestEntry(la Carte.entrée aîné) de la fonction.
en java, vous devez utiliser LinkedHashMap et fermer à jamais HashMap. Meilleur LRU cartes utilisent une certaine forme de Carte w/ lien nœuds, c'est à dire qu'il peut être mis en œuvre avec la recherche binaire rouge-noir et un lien (précédent/suivant) nœuds de côté parent/gauche/droite/valeur/rouge|noir champs. Ou ce LinkedHashMap est: arbre en fonction des seaux w/ prev/next.
HashMap, HashTable, LinkedHashMap en Java sont mis en œuvre à l'aide de tables de hachage c'est à dire de tableau et linéaire de sondage pour la résolution de collision. Ils ne sont pas mis en œuvre comme rouge noir des arbres
Je n'ai jamais dit qu'ils sont rouge-noir, vous pouvez voir TreeMap, ajoutant prev/next pour les nœuds n'est pas dur, j'ai une carte du même type pour des primitifs doubles, c'est à dire rouge-noir w/ prev/next entre les nœuds.
yup l'ajout suivant/précédent dans une structure d'arbre de données n'est pas difficile, mais je me demande wont u besoin de modifier l'interne TreeMap classe si tu veux ajouter prev/next nœud?
OriginalL'auteur Amm Sokun | 2011-06-18
Vous devez vous connecter pour publier un commentaire.
Si vous voulez un cache LRU, le plus simple en Java est LinkedHashMap. Le comportement par défaut est FIFO cependant, vous pouvez change "accéder à la commande", ce qui en fait un cache LRU.
Remarque: j'ai l'aide de la constructeur qui change de la collection de la plus récente d'abord pour les plus récemment utilisés en premier.
De la Javadoc
Quand accessOrder est
true
la LinkedHashMap re-arrange la commande de la carte à chaque fois que vous obtenez() une entrée qui n'est pas le dernier.De cette façon, l'entrée la plus ancienne est du moins ce qui est utilisé récemment.
votre code sera supprimer aîné d'entrée et de pas moins récemment utilisé. aîné d'entrée pourraient être utilisées le plus récemment l'entrée aussi.
lorsque vous utilisez changer le mode de classement de "l'accès de l'ordre", il devient et cache LRU. (Voir ma réponse mis à jour)
Excellent !!! Ne savais pas qu'on peut modifier pour accéder à la commande. Testé, fonctionne très bien. La plupart des implémentations de l'utilisation de la combinaison de hashmap et DLL
Pourquoi avez-vous utilisé cacheSize comme (4/3 * cacheSize) au lieu de cacheSize et aussi le facteur de charge 0,75 f, quelle est la nécessité de donner un facteur de charge lors de notre table de hachage n'excédera pas la première cacheSize(nous avons l'itération n pages sur notre table de hachage).
OriginalL'auteur Peter Lawrey
Normalement, LRU, les caches sont représentés LIFO structures - une seule file d'attente d'éléments. Si celui fourni par votre niveau ne vous permet pas de supprimer des objets du milieu, par exemple, pour les mettre sur le dessus, alors vous peut-être rouler vos propres.
oui, il peut être O(1), voir mon commentaire ci-dessus, LinkedHashMap en java est O(1)
LinkedHashMap fournit un moyen de parcourir les clés présents dans la carte, mais de trouver la moins récente paire clé/valeur aura besoin d'une recherche séquentielle
la première (à retirer) est O(1). carte.entrySet().iterator().next() ou vous pouvez remplacer
removeEldestEntry(Map.Entry<K,V> eldest)
, LinkedHashMap ne fournit pas de queue (j'.e le dernier ajout/touché) et d'inverser traverse bien qu'il est pratiquement pris en charge par la structure.Si l'élément à supprimer est quelque part au milieu de la liste, puis l'habitude de u besoin pour atteindre à cet élément afin de le supprimer?
OriginalL'auteur Puppy
Considérant le cache permet l'accès simultané, le problème de la bonne conception de cache LRU se résume à:
a) Peut-on éviter l'utilisation de mutex tout en mettant à jour les deux structures(cache de la structure et de la LRU, de la structure).
b) la lecture (get) le fonctionnement du cache exiger mutex?
Plus en détail: - Dire si l'on met en œuvre à l'aide de java.util.de façon concomitante.ConcuurentHashMap(cache de la structure) et java.util.de façon concomitante.ConcurrentLinkedQueue(LRU structure)
a)de Verrouillage à la fois ces deux structures sur les opérations d'édition - addEntry(), removeEntry(), evictEntries (), etc.
b) ci-dessus pourrait probablement passer pour de la lenteur des opérations d'écriture, mais le problème est le même pour la lecture (get) de l'opération, nous avons besoin d'appliquer de verrouillage sur les deux structures. Parce que, obtenir signifie mettre l'entrée à l'avant de la file d'attente pour LRU stratégie.(En supposant que les entrées ont été supprimées à partir de la fin de la file d'attente).
Utilisation simultanée efficace des structures comme ConcurrentHashMap et attendre gratuit ConcurrentLinkedQueue et puis mettre un verrou sur eux est de perdre la raison.
J'ai mis en place un cache LRU, avec la même approche, cependant, la LRU structuré a été mis à jour de manière asynchrone en éliminant le besoin d'utiliser un mutex si l'accès à ces structures. LRU est un détail interne de la Cache et peut être mis en œuvre sans affecter les utilisateurs de la cache.
Plus tard, j'ai aussi lu à propos de ConcurrentLinkedHashMap
https://code.google.com/p/concurrentlinkedhashmap/
Et trouve que c'est aussi essayer de faire la même chose. Pas utilisé cette structure, mais peut-être peut-être un bon ajustement.
OriginalL'auteur aditrip
J'aimerais développer certaines de ces suggestions avec deux implémentations possibles. Un pas thread-safe, et qui pourrait être.
Ici est une version la plus simple avec une unité de test qui montre que cela fonctionne.
D'abord le non-cumul version:
Le vrai drapeau de la piste de l'accès des gets et met. Voir La Documentation Javadoc. Le removeEdelstEntry sans le vrai drapeau du constructeur serait tout simplement de mettre en œuvre une FIFO cache (voir les notes ci-dessous sur la FIFO et removeEldestEntry).
Voici le test qui prouve qu'il fonctionne comme un cache LRU:
Maintenant pour la version simultanée...
Vous pouvez voir pourquoi je couvre le non-cumul de la version première. Le ci-dessus tente de créer des bandes de réduire de verrouillage. Nous avons donc c'hachages de la clé et de la recherche alors que de hachage pour trouver la cache. Cela fait de la limite de taille de plus d'une suggestion/deviner rugueuse à l'intérieur d'un juste montant de l'erreur en fonction de comment bien répartir vos clés de l'algorithme de hachage est.
OriginalL'auteur RickHigh
Énoncé Du Problème :
Créer cache LRU et Employé du magasin d'objet Max =5 objets et de trouver qui connectez-vous d'abord et après ....
LRUObjectCacheExample
Résultats:
OriginalL'auteur vaquar khan
LinkedHashMap vous permet de remplacer la removeEldestEntry fonction de sorte que chaque fois qu'un est exécuté, vous pouvez spécifier s'il faut supprimer l'entrée la plus ancienne ou pas, permettant ainsi la mise en œuvre d'une LRU.
OriginalL'auteur ravthiru
Pour O(1) accès nous avons besoin d'une table de hachage et de maintenir l'ordre, nous pouvons utiliser DLL.
De base algo - à partir de numéro de page, nous pouvons obtenir DLL nœud à l'aide de la table de hachage. Si la page existe, nous pouvons déplacer le nœud à la tête de la DLL d'autre insérez le nœud de la bibliothèque et de la table de hachage. Si la taille de la DLL est plein, nous pouvons retirer le moins récemment utilisé nœud de la queue.
Voici une implémentation basée sur liste doublement chaînée et unordered_map en C++.
OriginalL'auteur learner
L'extension de Peter Lawrey la réponse de
La
removeEldestEntry(java.util.Map.Entry)
méthode peut être redéfinie à imposer une politique de suppression des adressages périmés automatiquement lorsque de nouveaux mappages sont ajoutés à la carte.Donc LinkedHashMap du FIFO comportement peut être changé pour faire LRU
vous aurez accès commande (lru) par la mise en ordre d'accès au pavillon LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder)
D'accord .. reprendre mon commentaire
OriginalL'auteur bhushan5640
OriginalL'auteur anonymous