教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 【缓存算法】之LFU算法golang简单实现

【缓存算法】之LFU算法golang简单实现

发布时间:2021-12-19   编辑:jiaochengji.com
教程集为您提供【缓存算法】之LFU算法golang简单实现等资源,欢迎您收藏本站,我们将为您提供最新的【缓存算法】之LFU算法golang简单实现资源
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;"><path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"/></svg><h4>前言:</h4>

缓存算法,一般有LFU和LRU、FIFO等;
LFU:(Least Frequently Used)从字面可以理解,根据历史访问频率来淘汰数据,核心思想就是“如果数据过去被访问多次,那么将来被访问的频率也就越高”;
LRU:(Least Recently Used) 最近最少使用,根据历史访问记录来淘汰数据,“如果数据最近被访问过,那么将来访问的几率也就会很高”。
FIFO:(First In First Out) 先进先出,类似于队列,如果一个数据先进入缓存中,则应该先被淘汰,可以理解为,当缓存满的时候,应当把最先进入缓存的数据给淘汰掉。

那么今天谈一下LRU算法的实现:
LRU相当于把数据按照时间排序,这个需求可以是使用栈,或者链表实现,使用链表的话,删除和插入的时间复杂度要小一些,如果从链表头部插入元素的话,越靠近头部的元素就是新的数据,越靠近尾部的数据就是旧数据,我们进行淘汰的时候,只需要把尾部的元素删除就可以了。

实现逻辑可以参考:https://mp.weixin.qq.com/s/oXv03m1J8TwtHwMJEZ1ApQ
代码如下:

<pre><code class="lang-go hljs"><span class="token keyword">package</span> main <span class="token keyword">import</span> <span class="token punctuation">(</span> <span class="token string">"log"</span> <span class="token string">"sync"</span> <span class="token punctuation">)</span> <span class="token keyword">type</span> LFU <span class="token keyword">struct</span> <span class="token punctuation">{</span> Cap <span class="token builtin">int</span> KeyToValue <span class="token keyword">map</span><span class="token punctuation">[</span><span class="token builtin">int</span><span class="token punctuation">]</span><span class="token builtin">int</span> KeyToFreq <span class="token keyword">map</span><span class="token punctuation">[</span><span class="token builtin">int</span><span class="token punctuation">]</span><span class="token builtin">int</span> FreqToKeysMap <span class="token keyword">map</span><span class="token punctuation">[</span><span class="token builtin">int</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">int</span> MinFreq <span class="token builtin">int</span> <span class="token punctuation">}</span> <span class="token keyword">var</span> G_LFU <span class="token operator">*</span>LFU <span class="token keyword">var</span> lock <span class="token operator">*</span>sync<span class="token punctuation">.</span>Mutex <span class="token operator">=</span> <span class="token function">new</span><span class="token punctuation">(</span>sync<span class="token punctuation">.</span>Mutex<span class="token punctuation">)</span> <span class="token keyword">func</span> <span class="token function">NewLFU</span><span class="token punctuation">(</span><span class="token builtin">cap</span> <span class="token builtin">int</span><span class="token punctuation">)</span><span class="token operator">*</span>LFU<span class="token punctuation">{</span> <span class="token keyword">if</span> G_LFU <span class="token operator">==</span> <span class="token boolean">nil</span><span class="token punctuation">{</span> lock<span class="token punctuation">.</span><span class="token function">Lock</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">defer</span> lock<span class="token punctuation">.</span><span class="token function">Unlock</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">if</span> G_LFU <span class="token operator">==</span> <span class="token boolean">nil</span><span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token operator">&</span>LFU<span class="token punctuation">{</span>Cap<span class="token punctuation">:</span><span class="token builtin">cap</span><span class="token punctuation">,</span>KeyToValue<span class="token punctuation">:</span><span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">map</span><span class="token punctuation">[</span><span class="token builtin">int</span><span class="token punctuation">]</span><span class="token builtin">int</span><span class="token punctuation">)</span><span class="token punctuation">,</span> KeyToFreq<span class="token punctuation">:</span><span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">map</span><span class="token punctuation">[</span><span class="token builtin">int</span><span class="token punctuation">]</span><span class="token builtin">int</span><span class="token punctuation">)</span><span class="token punctuation">,</span> FreqToKeysMap<span class="token punctuation">:</span><span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">map</span><span class="token punctuation">[</span><span class="token builtin">int</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">int</span><span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> G_LFU <span class="token punctuation">}</span> <span class="token comment">/* todo : 从valueMap 中查找相应的键值对 如果存在,也需要更新下key对应的频率 (使用Map 栈的结构) 推荐使用map 链表的结构 */</span> <span class="token keyword">func</span> <span class="token punctuation">(</span>self <span class="token operator">*</span>LFU<span class="token punctuation">)</span><span class="token function">get</span><span class="token punctuation">(</span>key <span class="token builtin">int</span><span class="token punctuation">)</span><span class="token builtin">int</span><span class="token punctuation">{</span> <span class="token comment">//1.从value map 中获取</span> v<span class="token punctuation">,</span>ok <span class="token operator">:=</span> self<span class="token punctuation">.</span>KeyToValue<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token keyword">if</span> <span class="token operator">!</span>ok<span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token operator">-</span><span class="token number">1</span> <span class="token punctuation">}</span> <span class="token comment">//2.需要跟新FreqMap</span> self<span class="token punctuation">.</span><span class="token function">increaseFreq</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span> <span class="token keyword">return</span> v <span class="token punctuation">}</span> <span class="token keyword">func</span> <span class="token punctuation">(</span>self <span class="token operator">*</span>LFU<span class="token punctuation">)</span><span class="token function">put</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span>val <span class="token builtin">int</span><span class="token punctuation">)</span><span class="token builtin">int</span><span class="token punctuation">{</span> <span class="token keyword">if</span> self<span class="token punctuation">.</span>Cap <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token operator">-</span><span class="token number">1</span> <span class="token punctuation">}</span> <span class="token comment">//分为两种情况 key 不存在, 存在</span> <span class="token comment">//key 存在, 需要更新freqMap</span> <span class="token keyword">if</span> <span class="token boolean">_</span><span class="token punctuation">,</span>exist <span class="token operator">:=</span> self<span class="token punctuation">.</span>KeyToValue<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">;</span>exist<span class="token punctuation">{</span> <span class="token comment">//更新最新的值</span> self<span class="token punctuation">.</span>KeyToValue<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">=</span> val <span class="token comment">//更新频率</span> self<span class="token punctuation">.</span><span class="token function">increaseFreq</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token number">0</span> <span class="token punctuation">}</span> <span class="token comment">//todo 如果不存在 需要判断容量是不是满了?</span> <span class="token comment">//如果容量满了 需要根据最小的minFreq,找到对应的key(列表) 删除里面的key</span> <span class="token keyword">if</span> <span class="token function">len</span><span class="token punctuation">(</span>self<span class="token punctuation">.</span>KeyToValue<span class="token punctuation">)</span> <span class="token operator">>=</span> self<span class="token punctuation">.</span>Cap<span class="token punctuation">{</span> <span class="token comment">// full</span> self<span class="token punctuation">.</span><span class="token function">removeMinFreq</span><span class="token punctuation">(</span>self<span class="token punctuation">.</span>MinFreq<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token comment">//如果容量未满 valueMap里面新加一个key,并且加入到freqMap key=1 对应的列表中</span> <span class="token comment">//同时更新最小的minFreq = 1</span> <span class="token comment">//更新 KV</span> self<span class="token punctuation">.</span>KeyToValue<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">=</span> val <span class="token comment">//更新 KF</span> self<span class="token punctuation">.</span>KeyToFreq<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token number">1</span> self<span class="token punctuation">.</span>MinFreq <span class="token operator">=</span> <span class="token number">1</span> <span class="token comment">//使用 map 栈来是实现</span> self<span class="token punctuation">.</span>FreqToKeysMap<span class="token punctuation">[</span>self<span class="token punctuation">.</span>MinFreq<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">append</span><span class="token punctuation">(</span>self<span class="token punctuation">.</span>FreqToKeysMap<span class="token punctuation">[</span>self<span class="token punctuation">.</span>MinFreq<span class="token punctuation">]</span><span class="token punctuation">,</span>key<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token number">0</span> <span class="token punctuation">}</span> <span class="token comment">/* 增加key对应的频率 */</span> <span class="token keyword">func</span> <span class="token punctuation">(</span>self <span class="token operator">*</span>LFU<span class="token punctuation">)</span><span class="token function">increaseFreq</span><span class="token punctuation">(</span>key <span class="token builtin">int</span> <span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token comment">//todo 根据key 获取 freq</span> freq<span class="token punctuation">,</span><span class="token boolean">_</span> <span class="token operator">:=</span> self<span class="token punctuation">.</span>KeyToFreq<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token comment">//更新 KF</span> self<span class="token punctuation">.</span>KeyToFreq<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">=</span> freq <span class="token operator"> </span> <span class="token number">1</span> <span class="token comment">//todo 移除 freqtokeys 建议用链表删除(下面代码使用栈实现)</span> <span class="token keyword">for</span> k<span class="token punctuation">,</span>v <span class="token operator">:=</span> <span class="token keyword">range</span> self<span class="token punctuation">.</span>FreqToKeysMap<span class="token punctuation">[</span>freq<span class="token punctuation">]</span><span class="token punctuation">{</span> <span class="token keyword">if</span> key <span class="token operator">==</span> v <span class="token punctuation">{</span> self<span class="token punctuation">.</span>FreqToKeysMap<span class="token punctuation">[</span>freq<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">append</span><span class="token punctuation">(</span>self<span class="token punctuation">.</span>FreqToKeysMap<span class="token punctuation">[</span>freq<span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">:</span>k<span class="token punctuation">]</span><span class="token punctuation">,</span>self<span class="token punctuation">.</span>FreqToKeysMap<span class="token punctuation">[</span>freq<span class="token punctuation">]</span><span class="token punctuation">[</span>k<span class="token operator"> </span><span class="token number">1</span><span class="token punctuation">:</span><span class="token punctuation">]</span><span class="token operator">...</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token comment">//todo 将 key 加入到freq 1 对应的列表中</span> self<span class="token punctuation">.</span>FreqToKeysMap<span class="token punctuation">[</span>freq<span class="token operator"> </span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">append</span><span class="token punctuation">(</span>self<span class="token punctuation">.</span>FreqToKeysMap<span class="token punctuation">[</span>freq<span class="token operator"> </span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span>key<span class="token punctuation">)</span> <span class="token comment">//需要判断freqToKeys的列表,如果空了,需要移除这个freq</span> <span class="token keyword">if</span> <span class="token function">len</span><span class="token punctuation">(</span>self<span class="token punctuation">.</span>FreqToKeysMap<span class="token punctuation">[</span>freq<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">{</span> <span class="token function">delete</span><span class="token punctuation">(</span>self<span class="token punctuation">.</span>FreqToKeysMap<span class="token punctuation">,</span>freq<span class="token punctuation">)</span> <span class="token comment">//如果这个freq是 minFreq 需要更新一下minFreq</span> <span class="token keyword">if</span> freq <span class="token operator">==</span> self<span class="token punctuation">.</span>MinFreq<span class="token punctuation">{</span> self<span class="token punctuation">.</span>MinFreq<span class="token operator"> </span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token comment">/*todo 从最小频率对应的数组中,删除最初加入的key */</span> <span class="token keyword">func</span> <span class="token punctuation">(</span>self <span class="token operator">*</span>LFU<span class="token punctuation">)</span><span class="token function">removeMinFreq</span><span class="token punctuation">(</span>minFreq <span class="token builtin">int</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token comment">//获取要删除的key</span> <span class="token keyword">var</span> delKey <span class="token builtin">int</span> <span class="token keyword">if</span> <span class="token function">len</span><span class="token punctuation">(</span>self<span class="token punctuation">.</span>FreqToKeysMap<span class="token punctuation">)</span> <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">{</span> <span class="token comment">//删除栈顶</span> delKey <span class="token operator">=</span> self<span class="token punctuation">.</span>FreqToKeysMap<span class="token punctuation">[</span>minFreq<span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> self<span class="token punctuation">.</span>FreqToKeysMap<span class="token punctuation">[</span>minFreq<span class="token punctuation">]</span> <span class="token operator">=</span> self<span class="token punctuation">.</span>FreqToKeysMap<span class="token punctuation">[</span>minFreq<span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token punctuation">:</span><span class="token function">len</span><span class="token punctuation">(</span>self<span class="token punctuation">.</span>FreqToKeysMap<span class="token punctuation">[</span>minFreq<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token comment">//删除 KV 表</span> <span class="token function">delete</span><span class="token punctuation">(</span>self<span class="token punctuation">.</span>KeyToValue<span class="token punctuation">,</span>delKey<span class="token punctuation">)</span> <span class="token comment">//更新 KF表</span> <span class="token function">delete</span><span class="token punctuation">(</span>self<span class="token punctuation">.</span>KeyToFreq<span class="token punctuation">,</span>delKey<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> cache <span class="token operator">:=</span> <span class="token function">NewLFU</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span> cache<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">10</span><span class="token punctuation">)</span> cache<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">20</span><span class="token punctuation">)</span> log<span class="token punctuation">.</span><span class="token function">Printf</span><span class="token punctuation">(</span><span class="token string">"key = 1;value = %d"</span><span class="token punctuation">,</span>cache<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span> log<span class="token punctuation">.</span><span class="token function">Printf</span><span class="token punctuation">(</span><span class="token string">"key = 2;value = %d"</span><span class="token punctuation">,</span>cache<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">//2020/08/07 10:39:47 key = 1;value = 10</span> <span class="token comment">//2020/08/07 10:39:47 key = 2;value = 20</span> <span class="token comment">//todo 容量已满 所以会删除 key = 1</span> cache<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">30</span><span class="token punctuation">)</span> log<span class="token punctuation">.</span><span class="token function">Printf</span><span class="token punctuation">(</span><span class="token string">"key = 1;value = %d"</span><span class="token punctuation">,</span>cache<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">//2020/08/07 10:39:47 key = 1;value = -1</span> <span class="token punctuation">}</span> </code></pre>

主要是:在新增key的时候,需要考虑key是否存在,如果存在了,那么容量是否大于初始化时候设定的cap,如果大于cap了,那么就需要删除旧的key.可以参考下图的流程图实现:

到此这篇关于“【缓存算法】之LFU算法golang简单实现”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
SpringMVC整合EhCache实现对象缓存的详解
【缓存算法】之LFU算法golang简单实现
数据结构和算法(Golang实现)(10)基础知识-算法复杂度主方法
Golang 一致性Hash算法实现
Go从入门到精通系列视频之go编程语言密码学哈希算法
使用 PHP 实现 LRU 缓存淘汰算法
php页面缓存的例子(减经cpu与mysql负担)
MySQL新手入门教程:mysql优化入门
Golang缓存生态
谈谈一致性哈希算法及其 Golang 实现(含负载均衡算法概述)

[关闭]
~ ~