Maison développement back-end Golang Analyse détaillée de l'algorithme de cache LRU dans Golang.

Analyse détaillée de l'algorithme de cache LRU dans Golang.

Jun 19, 2023 pm 08:28 PM
golang lru缓存算法 详细解析

Lors du développement d'un système efficace et stable, la mise en cache est une méthode d'optimisation indispensable. L'un des algorithmes de mise en cache les plus courants est l'algorithme LRU. L'algorithme LRU est l'algorithme « le moins récemment utilisé », qui peut éliminer les éléments les moins récemment utilisés en enregistrant l'utilisation de chaque élément dans le cache afin de maximiser l'efficacité d'utilisation du cache. Dans Golang, l'algorithme de cache LRU peut également être facilement implémenté.

Cet article présentera en détail l'implémentation de l'algorithme de cache LRU dans Golang, y compris comment utiliser une liste chaînée bidirectionnelle et une table de hachage pour l'implémenter, comment mettre à jour et éliminer le cache, et comment effectuer des threads. opérations sécuritaires.

  1. Utilisez une liste doublement chaînée et une table de hachage pour implémenter l'algorithme de mise en cache LRU

Dans Golang, la liste doublement chaînée est une structure de données de base qui peut facilement implémenter l'algorithme de mise en cache LRU. La méthode de mise en œuvre spécifique consiste à encapsuler chaque élément du cache dans un nœud et à utiliser une liste doublement chaînée pour gérer ces nœuds. Dans le même temps, une table de hachage (carte) est utilisée pour enregistrer l'emplacement de chaque nœud afin de faciliter une recherche et une mise à jour rapides.

Ce qui suit est la structure de code de base pour implémenter l'algorithme de cache LRU dans Golang :

type Node struct {
    Key  int
    Val  int
    Prev *Node
    Next *Node
}

type LRUCache struct {
    Size       int
    Capacity   int
    Cache      map[int]*Node
    Head, Tail *Node
}

func Constructor(capacity int) LRUCache {
    head, tail := &Node{}, &Node{}
    head.Next, tail.Prev = tail, head
    return LRUCache{
        Cache:     make(map[int]*Node),
        Capacity:  capacity,
        Size:      0,
        Head:      head,
        Tail:      tail,
    }
}

func (l *LRUCache) Get(key int) int {
    if node, ok := l.Cache[key]; ok {
        l.MoveToHead(node)
        return node.Val
    }
    return -1
}

func (l *LRUCache) Put(key, val int) {
    if node, ok := l.Cache[key]; ok {
        node.Val = val
        l.MoveToHead(node)
        return
    }
    node := &Node{Key: key, Val: val}
    l.Cache[key] = node
    l.AddToHead(node)
    l.Size++
    if l.Size > l.Capacity {
        removed := l.RemoveTail()
        delete(l.Cache, removed.Key)
        l.Size--
    }
}

func (l *LRUCache) MoveToHead(node *Node) {
    l.RemoveNode(node)
    l.AddToHead(node)
}

func (l *LRUCache) RemoveNode(node *Node) {
    node.Prev.Next = node.Next
    node.Next.Prev = node.Prev
}

func (l *LRUCache) AddToHead(node *Node) {
    node.Prev = l.Head
    node.Next = l.Head.Next
    l.Head.Next.Prev = node
    l.Head.Next = node
}

func (l *LRUCache) RemoveTail() *Node {
    node := l.Tail.Prev
    l.RemoveNode(node)
    return node
}
Copier après la connexion

Dans le code ci-dessus, LRUCache est une structure, comprenant une table de hachage Cache , Un pointeur Head et un pointeur Tail sont utilisés pour enregistrer les nœuds de tête et de queue de la liste doublement chaînée et la position de chaque élément dans le cache. Parmi eux, la clé de la table de hachage Cache est la clé de l'élément, et la valeur est le pointeur de nœud de l'élément Head pointe vers le nœud principal de l'élément ; liste doublement chaînée, et Tail Pointe vers le nœud de queue. Size représente le nombre d'éléments dans le cache actuel, et Capacity représente la capacité maximale du cache. LRUCache是一个结构体,包含一个Cache哈希表、一个Head指针和一个Tail指针,用于记录双向链表的头尾节点和缓存中每个元素的位置。其中,Cache哈希表的键是元素的键,值是元素的节点指针;Head指向双向链表的头节点,Tail指向尾节点。Size表示当前缓存中元素的个数,Capacity表示缓存的最大容量。

Constructor函数中,我们初始化了一个空的双向链表,并返回一个LRUCache结构体。在Get函数中,我们首先判断缓存中是否存在指定的元素,如果存在,则将该元素移动到链表头部,并返回其值;否则返回-1。在Put函数中,我们首先判断缓存中是否存在指定的元素,如果存在,则更新该元素的值,将其移动到头部;否则新增一个元素,并将其添加到头部。如果缓存大小超过了最大容量,则删除最近最少使用的元素,并将其从哈希表中删除。

MoveToHeadRemoveNodeAddToHeadRemoveTail分别对应实现双向链表的节点移动和删除操作,具体实现方式在代码中给出。

  1. 更新与淘汰缓存

在使用LRU缓存算法时,需要保证缓存中元素的访问顺序按照最近使用的时间顺序排列。每当从缓存中读取或更新一个元素时,需要将其移动到链表的头部;同时,当缓存大小超过最大容量时,需要淘汰最近最少使用的元素,即链表中的最后一个元素。

下面是MoveToHead函数的实现方式:

func (l *LRUCache) MoveToHead(node *Node) {
    l.RemoveNode(node)
    l.AddToHead(node)
}
Copier après la connexion

MoveToHead函数接受一个指向缓存节点的指针node作为参数,首先从链表中删除该节点,然后将该节点添加到链表头部。

下面是RemoveTail函数的实现方式:

func (l *LRUCache) RemoveTail() *Node {
    node := l.Tail.Prev
    l.RemoveNode(node)
    return node
}
Copier après la connexion

RemoveTail函数返回链表中的最后一个节点,并将该节点从链表中删除。

  1. 线程安全操作

在多线程环境下,需要保证LRU缓存操作的线程安全性。为此,我们可以使用sync包中提供的互斥锁(Mutex)来实现。具体方式是,在需要进行缓存操作的函数中加入互斥锁的操作,避免同时对缓存进行读写操作。下面是Golang中实现LRU缓存算法的线程安全版本的代码结构:

type LRUCache struct {
    Size       int
    Capacity   int
    Cache      map[int]*Node
    Head, Tail *Node
    Mutex      sync.Mutex
}

func (l *LRUCache) Get(key int) int {
    l.Mutex.Lock()
    defer l.Mutex.Unlock()

    ...
}

func (l *LRUCache) Put(key, val int) {
    l.Mutex.Lock()
    defer l.Mutex.Unlock()

    ...
}

...
Copier après la connexion

上面的代码中,我们在结构体LRUCache中添加了一个Mutex

Dans la fonction Constructeur, nous initialisons une liste vide doublement chaînée et renvoyons une structure LRUCache. Dans la fonction Get, nous déterminons d'abord si l'élément spécifié existe dans le cache. S'il existe, déplaçons l'élément en tête de la liste chaînée et renvoyons sa valeur ; sinon, -1 est renvoyé ; Dans la fonction Put, nous déterminons d'abord si l'élément spécifié existe dans le cache. S'il existe, mettons à jour la valeur de l'élément et déplaçons-le vers la tête, sinon, ajoutons un nouvel élément et ajoutons-le ; à la tête. Si la taille du cache dépasse la capacité maximale, l'élément le moins récemment utilisé est supprimé et supprimé de la table de hachage.
  1. MoveToHead, RemoveNode, AddToHead et RemoveTail correspondent respectivement aux opérations de déplacement et de suppression de nœud du double lien list, en particulier L'implémentation est donnée dans le code.
    1. Mettre à jour et éliminer le cache

      🎜Lors de l'utilisation de l'algorithme de cache LRU, il est nécessaire de s'assurer que la séquence d'accès aux éléments du cache est organisée dans l'ordre temporel le plus récemment utilisé. Chaque fois qu'un élément est lu ou mis à jour à partir du cache, il doit être déplacé en tête de la liste chaînée en même temps, lorsque la taille du cache dépasse la capacité maximale, l'élément le moins récemment utilisé, c'est-à-dire le dernier élément ; dans la liste chaînée, doit être éliminé. 🎜🎜Ce qui suit est l'implémentation de la fonction MoveToHead : 🎜rrreee🎜La fonction MoveToHead accepte un pointeur vers le nœud de cache node comme paramètre , d'abord à partir de la liste chaînée Supprimez le nœud de la liste et ajoutez-le en tête de la liste chaînée. 🎜🎜Ce qui suit est l'implémentation de la fonction RemoveTail : 🎜rrreee🎜La fonction RemoveTail renvoie le dernier nœud de la liste chaînée et supprime le nœud de la liste chaînée. 🎜
        🎜Opération thread-safe🎜🎜🎜Dans un environnement multithread, il est nécessaire d'assurer la sécurité des threads des opérations de cache LRU. Pour ce faire, nous pouvons utiliser le mutex fourni dans le package de synchronisation. La méthode spécifique consiste à ajouter des opérations de verrouillage mutex aux fonctions qui nécessitent des opérations de cache pour éviter de lire et d'écrire dans le cache en même temps. Voici la structure de code pour implémenter la version thread-safe de l'algorithme de cache LRU dans Golang : 🎜rrreee🎜Dans le code ci-dessus, nous avons ajouté un membre Mutex à la structure LRUCache code>, utilisé pour l'exclusion mutuelle synchrone des opérations de cache. Avant d'effectuer toute opération de mise en cache, nous devons obtenir le verrou mutex. Dans tous les cas, qu'il s'agisse de lire ou de modifier le cache, nous devons libérer le mutex. 🎜🎜🎜Résumé🎜🎜🎜Cet article présente l'implémentation de l'algorithme de cache LRU dans Golang, y compris l'utilisation d'une liste doublement chaînée et d'une table de hachage, la mise à jour et l'élimination du cache et les opérations thread-safe. L'algorithme de cache LRU est un algorithme de cache simple et efficace qui est largement utilisé dans le développement réel. Lorsque vous utilisez Golang pour écrire des applications de cache, vous pouvez utiliser l'algorithme de cache LRU pour améliorer les performances et la stabilité du système en fonction des besoins réels. 🎜

    Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

    Déclaration de ce site Web
    Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

    Outils d'IA chauds

    Undresser.AI Undress

    Undresser.AI Undress

    Application basée sur l'IA pour créer des photos de nu réalistes

    AI Clothes Remover

    AI Clothes Remover

    Outil d'IA en ligne pour supprimer les vêtements des photos.

    Undress AI Tool

    Undress AI Tool

    Images de déshabillage gratuites

    Clothoff.io

    Clothoff.io

    Dissolvant de vêtements AI

    AI Hentai Generator

    AI Hentai Generator

    Générez AI Hentai gratuitement.

    Article chaud

    R.E.P.O. Crystals d'énergie expliqués et ce qu'ils font (cristal jaune)
    2 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
    Repo: Comment relancer ses coéquipiers
    4 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
    Hello Kitty Island Adventure: Comment obtenir des graines géantes
    4 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
    Combien de temps faut-il pour battre Split Fiction?
    3 Il y a quelques semaines By DDD

    Outils chauds

    Bloc-notes++7.3.1

    Bloc-notes++7.3.1

    Éditeur de code facile à utiliser et gratuit

    SublimeText3 version chinoise

    SublimeText3 version chinoise

    Version chinoise, très simple à utiliser

    Envoyer Studio 13.0.1

    Envoyer Studio 13.0.1

    Puissant environnement de développement intégré PHP

    Dreamweaver CS6

    Dreamweaver CS6

    Outils de développement Web visuel

    SublimeText3 version Mac

    SublimeText3 version Mac

    Logiciel d'édition de code au niveau de Dieu (SublimeText3)

    Comment lire et écrire des fichiers en toute sécurité avec Golang ? Comment lire et écrire des fichiers en toute sécurité avec Golang ? Jun 06, 2024 pm 05:14 PM

    Lire et écrire des fichiers en toute sécurité dans Go est crucial. Les directives incluent : Vérification des autorisations de fichiers Fermeture de fichiers à l'aide de reports Validation des chemins de fichiers Utilisation de délais d'attente contextuels Le respect de ces directives garantit la sécurité de vos données et la robustesse de vos applications.

    Comment configurer le pool de connexions pour la connexion à la base de données Golang ? Comment configurer le pool de connexions pour la connexion à la base de données Golang ? Jun 06, 2024 am 11:21 AM

    Comment configurer le pool de connexions pour les connexions à la base de données Go ? Utilisez le type DB dans le package base de données/sql pour créer une connexion à la base de données ; définissez MaxOpenConns pour contrôler le nombre maximum de connexions simultanées ; définissez MaxIdleConns pour définir le nombre maximum de connexions inactives ; définissez ConnMaxLifetime pour contrôler le cycle de vie maximum de la connexion ;

    Similitudes et différences entre Golang et C++ Similitudes et différences entre Golang et C++ Jun 05, 2024 pm 06:12 PM

    Golang et C++ sont respectivement des langages de programmation de garbage collection et de gestion manuelle de la mémoire, avec des systèmes de syntaxe et de type différents. Golang implémente la programmation simultanée via Goroutine et C++ l'implémente via des threads. La gestion de la mémoire Golang est simple et le C++ offre de meilleures performances. Dans les cas pratiques, le code Golang est plus concis et le C++ présente des avantages évidents en termes de performances.

    Quelle est la courbe d'apprentissage de l'architecture du framework Golang ? Quelle est la courbe d'apprentissage de l'architecture du framework Golang ? Jun 05, 2024 pm 06:59 PM

    La courbe d'apprentissage de l'architecture du framework Go dépend de la familiarité avec le langage Go et le développement back-end ainsi que de la complexité du framework choisi : une bonne compréhension des bases du langage Go. Il est utile d’avoir une expérience en développement back-end. Les cadres qui diffèrent en complexité entraînent des différences dans les courbes d'apprentissage.

    Comment générer des éléments aléatoires à partir d'une liste dans Golang ? Comment générer des éléments aléatoires à partir d'une liste dans Golang ? Jun 05, 2024 pm 04:28 PM

    Comment générer des éléments aléatoires d'une liste dans Golang : utilisez rand.Intn(len(list)) pour générer un entier aléatoire dans la plage de longueur de la liste ; utilisez l'entier comme index pour obtenir l'élément correspondant de la liste.

    Comparaison des avantages et des inconvénients du framework Golang Comparaison des avantages et des inconvénients du framework Golang Jun 05, 2024 pm 09:32 PM

    Le framework Go se distingue par ses hautes performances et ses avantages en matière de concurrence, mais il présente également certains inconvénients, tels qu'être relativement nouveau, avoir un petit écosystème de développeurs et manquer de certaines fonctionnalités. De plus, les changements rapides et les courbes d’apprentissage peuvent varier d’un cadre à l’autre. Le framework Gin est un choix populaire pour créer des API RESTful en raison de son routage efficace, de sa prise en charge JSON intégrée et de sa puissante gestion des erreurs.

    Quelles sont les meilleures pratiques pour la gestion des erreurs dans le framework Golang ? Quelles sont les meilleures pratiques pour la gestion des erreurs dans le framework Golang ? Jun 05, 2024 pm 10:39 PM

    Meilleures pratiques : créer des erreurs personnalisées à l'aide de types d'erreurs bien définis (package d'erreurs) fournir plus de détails consigner les erreurs de manière appropriée propager correctement les erreurs et éviter de masquer ou de supprimer les erreurs Wrap si nécessaire pour ajouter du contexte

    instructions d'utilisation du document cadre Golang instructions d'utilisation du document cadre Golang Jun 05, 2024 pm 06:04 PM

    Comment utiliser la documentation du framework Go ? Déterminez le type de document : site Web officiel, référentiel GitHub, ressource tierce. Comprendre la structure de la documentation : prise en main, tutoriels approfondis, manuels de référence. Localisez les informations selon vos besoins : Utilisez la structure organisationnelle ou la fonction de recherche. Comprendre les termes et les concepts : lisez attentivement et comprenez les nouveaux termes et concepts. Cas pratique : Utiliser Beego pour créer un serveur web simple. Autre documentation du framework Go : Gin, Echo, Buffalo, Fiber.

    See all articles