FIFO算法
Posted zmycoco2
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了FIFO算法相关的知识,希望对你有一定的参考价值。
FIFO(First in First out),即先进先出算法,比如在超市购物之后会提着我们满满的购物车来到收银台排在结账队伍的最后,眼睁睁地看着前面的客户一个个离开,这就是一种先进先出机制,先排队的客户先行结账离开。其实在操作系统的设计理念中很多地方都利用到了先进先出的思想,比如作业调度机制,采用先来先服务的原则,为什么这个原则在很多地方都会用到呢?因为这个原则简单,符合人们的惯性思维,具备公平性,并且实现起来简单,通过直接使用数据结构中的队列即可实现。
FIFO是队列机制中最简单的,每个接口上都存在FIFO队列,表面上看FIFO队列并没有提供什么QoS(Quality of Service,服务质量)保证,甚至很多人认为FIFO严格意义上不算做一种队列技术,实则不然,FIFO是其他队列的基础,FIFO也会影响到衡量QoS的关键指标:报文的丢弃、延时、抖动。既然只有一个队列,自然不需要考虑如何对报文进行复杂的流量分类,也不用考虑下一个报文怎么拿、拿多少的问题,而且因为按顺序取报文,FIFO无需对报文重新排序。简化了这些实现其实也就提高了对报文时延的保证。
在FIFO Cache设计中,核心原则就是,如果一个数据最先进入缓存中,则应该最早被淘汰。也就是说,当缓存满的时候,应当把最先进入缓存的数据给淘汰掉。在设计一个基于FIFO算法的Cache(缓存)组件时应该支持以下操作:
n get(key):如果Cache中存在该key,则返回对应的value值,否则,返回-1;
n set(key,value):如果Cache中存在该key,则重置value值;如果不存在该key,则将该key插入到到Cache中,若Cache已满,则淘汰最早进入Cache的数据。
举个例子,假如Cache大小为3,访问数据序列为set(1,1)、set(2,2)、set(3,3)、set(4,4)、get(2)、set(5,5)则Cache中的数据变化如代码清单4-1所示。
代码清单4-1 Cache中的数据变化
(1,1) set(1,1)
(1,1) (2,2) set(2,2)
(1,1) (2,2) (3,3)set(3,3)
(2,2) (3,3) (4,4)set(4,4)
(2,2) (3,3) (4,4)get(2)
(3,3) (4,4) (5,5) set(5,5)
那么利用什么数据结构来这样的实现呢?我们可以利用一个双向链表保存数据,当来了新的数据之后便添加到链表末尾,如果Cache存满数据,则把链表头部数据删除,然后把新的数据添加到链表末尾。在访问数据的时候,如果在Cache中存在该数据的话,则返回对应的value值,否则返回-1。如果想提高访问效率,可以利用HashMap[1]来保存每个key在链表中对应的位置。
JDK自带的LinkedHashMap类是基于FIFO实现的,默认情况下LinkedHashMap就是按照添加顺序保存,我们只需重写下removeEldestEntry方法即可轻松实现一个FIFO缓存,简化版的实现代码如代码清单4-2所示。
代码清单4-2 LinkedHashMap的FIFO实现
final int cacheSize =5;
LinkedHashMap<Integer,String> lru = new LinkedHashMap<Integer, String>()
@Override
protected booleanremoveEldestEntry(Map.Entry<Integer, String> eldest)
return size() > cacheSize;
;
FIFO关心的就是队列长度问题,队列长度会影响到时延、抖动、丢包率。因为队列长度是有限的,有可能被填满,这就涉及该机制的丢弃原则。常见的一个丢弃原则叫作Tail Drop机制。简单地说就是该队列如果已经满了,那么后续进入的报文被丢弃,而没有什么机制来保证后续的报文可以挤掉已经在队列内的报文。在这种机制中,如果定义了较长的队列长度,那么队列不容易填满,被丢弃的报文也就少了,但是队列长度太长了会出现时延的问题,一般情况下时延的增加会导致抖动也增加。如果定义了较短的队列,时延的问题可以得到解决,但是发生Tail Drop的报文就变多了。
[1] 基于哈希表的Map接口的实现。详见第3章里面的介绍。
欢迎关注麦克叔叔每晚10点说,让我们一起交流与学习。
以上是关于FIFO算法的主要内容,如果未能解决你的问题,请参考以下文章