7
votes

Dictionnaire trié trié sur la valeur en C # (cache LRU)

Je veux mettre en place un LRU CACHE , où les éléments les moins récemment utilisés seront expulsés de manière asynchrone. Mon idée actuelle est d'utiliser un dictionnaire pour stocker la touche de paires et pour garder une trace des temps d'accès des objets, pour garder un SoirDdictionner . L'idée est que le thread ASYNC obtienne les éléments LRU à partir du type et supprimez du cache. Mais pour que cela fonctionne, triodictionnaire doit trier par valeur, ce qui ne le fait pas.

J'aurais pu utiliser un distinct au lieu du type pour garder la touche {KEY et Timeestamp} triés sur l'horodatage, mais je vais devoir faire un Recherche "linéaire" pour trouver la clé de la liste (lorsque je dois mettre à jour l'horodatage, lorsque la même clé est accessible à nouveau) - Je recherche une meilleure manière linéaire si possible. Quelqu'un peut-il partager des idées pour faire face à ce problème?

Alors, mon problème se résume à ceci:

Je dois rechercher des touches de recherche dans <= heure de connexion pour mettre à jour l'horodatage tout en même temps, capable d'obtenir les clés triées en fonction de l'horodatage.

Une façon dont on pensait était de conserver un trioddiction de <{clé, horodatage}, null> qui commande les touches basées sur la partie horodatage de {clé, horodatage }. Tandis que c'est bien, le problème est hashcode () devront simplement retourner clé.hashscode () (pour la recherche tout en mettant à jour horodatage), tandis que est égal () devrait également utiliser horodatage. Ainsi, est égal () et hashcode () est en conflit, alors soyait que ce n'est pas une bonne idée ...


1 commentaires

En d'autres termes, vous voulez que le type a agi comme une file d'attente prioritaire où la priorité est définie par horodatage? Quel est le problème avec le triodictionnaire ? Et btw il n'est pas O (1) c'est O (logn) - il est probablement mis en œuvre comme un arbre noir rouge.


4 Réponses :


4
votes

Ce que vous devriez faire est de conserver deux dictionnaires, un trié par temps et une par touches.

N'oubliez pas que les dictionnaires ne contiennent que des références à vos objets réels, de sorte que le dictionnaire que vous utilisez pour mettre à jour l'objet n'a pas d'importance. p>

Pour mettre à jour l'objet Créez une fonction qui mettra à jour les dictionnaires p> xxx pré>

maintenant, vous avez la trace du même objet à la fois de temps et de clé.

Je ne garde qu'une seule référence à un objet dans chronométré code>. Cela aide tout en retirant. P>

Vous pouvez continuer à couper votre dictionnaire chronométréObjects au besoin. P>

decource, tout en découpant, vous devez garder à l'esprit qu'il y a un autre dictionnaire keedObject code > Cela a une référence au même objet. Simplement appeler supprimer code> ne suffira pas. P>

Votre code Supprimer devra être comme ceci: P>

removeObject = timedObjects[timeToRemove];
timedObjects.Remove(timeToRemove);
keyedObject.Remove(removeObject.key);


3 commentaires

+1, deux dictionnaires. Notez que les arbres noirs rouges sont plutôt lents, mais ils donnent une performance assez cohérente. Pour une vitesse, un Treap est meilleur, mais les durables de fonctionnement des Treaps ont une écart type élevé.


Bonne idée .. mais je ne pense pas qu'il soit nécessaire de calculer le calendrier. L'élément à enlever (celui avec le moindre horodatage, ou le premier dans le timedObjects Siédmap) pourrait être trouvé par TimeDObjectS.First. Rite?


Oui, cela fonctionnerait si vous enleviez un seul objet à la fois. Mais vous avez mentionné vouloir utiliser un thread séparé pour éliminer les éléments. Cela signifie que votre dictionnaire TimeDObject peut devenir plus grand que la taille souhaitée pour le LRU, et vous devrez supprimer plusieurs éléments.



0
votes

Le type de carte que vous recherchez est (au moins en Java) appelé un linkedhashmap .

du Javadoc:

Table de hachage et mise en œuvre de la liste liée de l'interface de la carte, avec ordre d'itération prévisible. Cette implémentation diffère de HASHMAP en ce sens, il conserve une liste doublement liée à travers tout son Entrées. Cette liste liée définit l'ordre d'itération, qui est Normalement, l'ordre dans lequel les clés ont été insérées dans la carte ( l'insertion-commande ).

Un constructeur spécial est fourni pour créer une carte de hachage liée dont L'ordre d'itération est l'ordre dans lequel ses entrées ont été dernière accessible, à partir du moins récemment accédé à la plupart récemment ( ordre d'accès ). Ce type de carte est bien adapté à la construction de LRU caches .

Source pour LinkedHashMap de OpenJDK

afaik, il n'y a pas de mise en œuvre existante d'un linkedhashmap en C #. Cela étant dit, il ne devrait pas être terriblement difficile d'écrire un.


0 commentaires

0
votes

Au lieu de tri à titre de tri, écrivez votre propre liste liée et avez-vous le dictionnaire pointer sur ses nœuds comme des valeurs. Il sera toujours trié par l'horodatage, la mise à jour de l'horodatage et la suppression de l'élément utilisé le moins sévèrement utilisé sera O (1).


0 commentaires

0
votes

Voici la mise en œuvre du cache LRU en C #. o (1) efficace, mais pas le fil de sécurité; xxx


0 commentaires