面试不再怕,20行Python代码帮你搞懂LRU算法

LRU算法在后端工程师面试中,是一个比较常出现的题目,这篇文章带大家一起,理解LRU算法,并最终用Python轻松实现一个基于LRU算法的缓存。

缓存是什么

先看一张图,当我们访问网页,浏览器会给服务器发请求,服务器会经过一系列的运算,把页面返回给浏览器。

当有多个浏览器同时访问的时候,就会在短时间内发起多个请求,而服务器对每一个请求都要进行一系列相同的操作。重复工作不仅浪费资源,还可能导致响应速度变慢。

而缓存则可以把服务器返回的页面保存下来,当有其他的浏览器再访问时候,就不必劳服务器大驾,直接由缓存返回页面。为了保证响应速度,缓存通常是基于比较昂贵的硬件,比如RAM,这就决定了我们很难用大量的缓存把所有的页面都存下来,当恰好没有缓存浏览器请求的页面时,依然需要请求服务器。由于缓存容量有限,而数据量无限(互联网每天新产生的页面数无法估计),就需要把好刚用在刀刃上,缓存那些最有用的信息。

LRU是什么

LRU是一种缓存淘汰算法(在OS中也叫内存换页算法),由于缓存空间是有限的,所以要淘汰缓存中不常用的数据,留下常用的数据,达到缓存效率的最大化。LRU就是这样一种决定“淘汰谁留下谁”的算法,LRU是Least recently used的缩写,从字面意思“最近最少使用”,我们就可以理解LRU的淘汰规则。

LRU的淘汰逻辑

我们用一张图来描述LRU的淘汰逻辑,图中的缓存是一个列表结构,上面是头结点下面是尾节点,缓存容量为8(8个小格子):

- 有新数据(意味着数据之前没有被缓存过)时,加入到列表头

- 缓存到达最大容量时,需要淘汰数据多出来的数据,此时淘汰列表尾部的数据

- 当缓存中有数据被命中,则将数据移动到列表头部(相当于新加入缓存)

按上面的逻辑我们可以看到,一个数据如果经常被访问就会不断地被移动到列表头部,不会被淘汰出缓存,而越不经常访问的数据,越容易被挤出缓存。

20行Python代码实践LRU

接下来我们用Python来实现一个采用LRU算法的缓存。

从前面的文章中我们可以知道,缓存简化下来就两个功能,一个是往里装数据(缓存数据),一个是往外吐数据(命中缓存),所以我们的缓存对外只需要put和get两个接口就可以了。

按照前面的示意图,缓存内部我们只需要有一个列表(list)就可以实现LRU逻辑,不过用列表虽然能实现逻辑,但是在判断是否命中缓存时,速度可能非常慢(列表需要遍历才能知道数据有没有在里面)。在Python中,我们可以用基于hash的结构,比如字典(dict)或集合(set),来快速判断数据是否存在,解决列表实现的性能问题。但是字典和集合又是没有顺序的,如果能有一种既能排序,又是基于hash存储的数据结构,就好了。

在Python的collections包中,已经内置了这种实用的结构OrderedDict,OrderedDict是dict的子类,但是存储在内部的元素是有序的(列表的特点)。

解决了数据结构的问题,我们可以直接上手写逻辑了,代码如下:

 1class LRUCache:
 2
 3    def __init__(self, capacity):
 4        self.capacity = capacity
 5        self.queue = collections.OrderedDict()
 6
 7    def get(self, key):
 8        if key not in self.queue:
 9            return -1 // 要找的数据不在缓存中返回-1
10        value = self.queue.pop(key) // 将命中缓存的数据移除
11        self.queue[key] = value // 将命中缓存的数据重新添加到头部
12        return self.queue[key]
13
14
15    def put(self, key, value):
16        if key in self.queue: // 如果已经在缓存中,则先移除老的数据
17            self.queue.pop(key)
18        elif len(self.queue.items()) == self.capacity:
19            self.queue.popitem(last=False) // 如果不在缓存中并且到达最大容量,则把最后的数据淘汰
20        self.queue[key] = value // 将新数据添加到头部

下次面试在遇到LRU的题目,是不是就胸有成竹了?

原文发布于微信公众号 - Python私房菜(python-fans)

原文发表时间:2018-03-06

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏www.96php.cn

【fastadmin】踩坑第二发-CMS插件后台文章状态修改未通过前台报错

我们找到模板application\index\view\cms\archives\my.html 大概46-52行

5953
来自专栏Python、Flask、Django

Django处理json数据

1252
来自专栏FreeBuf

Hongcms 3.0.0后台SQL注入漏洞分析

* 本文作者:BlackWater,本文属FreeBuf原创奖励计划,未经许可禁止转载。

1306
来自专栏JavaEdge

操作系统之文件管理

将文件属性从外存拷到内存中打开文件表的一表目中 将其编号返回给用户。 系统可利用该编号到打开文件表中去查找。

36510
来自专栏黑泽君的专栏

c语言_文件操作_FILE结构体解释_涉及对操作系统文件FCB操作的解释_

  C将每个文件简单地作为顺序字节流(如下图)。每个文件用文件结束符结束,或者在特定字节数的地方结束,这个特定的字节数可以存储在系统维护的管理数据结构中。当打开...

1371
来自专栏Python攻城狮

mongoDB的安装及基本使用1.mongoDB简介2.MySQL的安装3.Mongodb下载安装3.安装pymongo4.Mongodb基本使用5.

MongoDB 是一个基于分布式文件存储的数据库。由 C++ 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。

2573
来自专栏我是攻城师

Spark任务两个小问题笔记

3277
来自专栏狂码一生

深入PHP FTP类的详解

FTP是一种文件传输协议,它支持两种模式,一种方式叫做Standard (也就是Active,主动方式),一种是 Passive (也就是PASV,被动方式)。...

4618
来自专栏黑泽君的专栏

day57_BOS项目_09

方式一:   第一步:获得activiti-eclipse-plugin.zip文件   第二步:将zip文件解压到eclipse的dropins目录中

912
来自专栏问天丶天问

Java代码远程操作oracle数据库,执行sql文件、备份、回滚

3892

扫码关注云+社区

领取腾讯云代金券