1. 主页
  2. 自己动手从0到1学写FAT32文件系统
  3. 第6章 缓冲区管理
  4. 缓冲区概述

缓冲区概述

内容纲要

缓冲区是一个意思的东西。

借助于缓冲区,原本外部很慢的外设存储器的读取速度会“变快”。其原理就在于将每次都需要读取外部存储器,转变为部分读取外部存储器,另一部分则从缓冲区读取。由于缓冲区位于内存中,读取速度相比读外部存储器要快很多。这样整体速度一平均,整体的平均读取速度就上来了,比原来全部读取外部设备要快。写的提速原理也是类似。

另一方面,借助于缓冲区,原本一些需要比较复杂实现的代码,可以在一定程度上得到简单。这点在后面应用缓冲区解决现有代码的一些问题时会得到体现。

主要内容

本课时从整体上介绍了一种缓冲区管理方案,用于优化存储设备的读写,从而提升FAT32文件系统的读写效率。

这里会结合一个图书馆的例子帮助理解。

假设你进入图书馆参考书籍写论文,书桌的位置离书架有一段距离。现在,你想找几本书来参考。你是跑到书架前,一次拿一本,再跑回书桌前看完,然后再去拿;还是一次拿多本,看完之后再去拿新的?

显然,从效率上来讲,你肯定会选择一次拿多本。不管有没有是不是真的有需要,先拿来再说。在写论文过程中,可能会在多本书之间来回参考。这时最好的方式是保持书放在桌上,确定不需要时再放回去。

拿好书之后,当我们需要参考其中一本书时,就可以直接从书桌上找到这本书,就没有必要再跑到书架上去拿。相比之下,这就大大的节省了时间,提升效率。

可能在某个时刻,你发现需要参考一本不在书架上的书。这时就需要跑到书架前去取新书。且慢!此时书桌已经满了,放不下新书了,那这时就需要决定要将哪本书放回去。该选择哪本书放回去呢?假设你不确定这些书在将来是否还会用到,那最好的办法就是看下哪本书是最久没有打开参考的。既然很久没打开,那很可能未来很长一段时间也不会打开,果断就选它啊。

结合这个例子,可以理解如下的缓存及其工作原理。

缓存的必要性

从大体上来讲,CPU本身运算的速度 > 读写内存的速度 >> 读写外部存储设备的效率。

以机械硬盘为例,其内部有电机放置的盘片,机械控制的碰头等组成。要读取指定位置的扇区,需要旋转盘片,移动磁头,这个过程是非常耗时的。即便是现在由Flash组成的固态硬盘,虽然没有这些机械装置,但其速度相对于CPU读写内存而言,也是很慢很慢的。

更别提嵌入式设备中通过SDIO总线、甚至是SPI总线挂载到MCU/CPU外部。这类设备的读写就要更慢更慢~

为了提升整体的读写效率,就要进行优化。有一种方法就是利用缓存。

其原理就是预先分配一定的内存,用于存储设备上某些扇区数据的拷贝,当需要读写这些扇区时,优先从这些内存中获取,从而避免了读写更慢的外部存储设备。

课程中列举了一个例子,如下图所示。

当需要频繁的连续读取某个扇区,如果我们明知该扇区的数据内容并没有发生改变,为什么不能在内存中直接放一份,然后要用的时候直接用这一份呢?反而是要每次都死板的从外部读进来,岂不是大大降低读取速度?

所以,我们有理解增加这样一种缓存机制,来提升文件的读取效率。

你相当于CPU,书桌可以看作是内存,书桌上的书可以看作是缓存,书架可以看作是外部存储设备。

相比每次跑去书架取一本书,同时将之前取的书放回去,更明智的做法是将之前的书留在桌上,后面需要的时候就不用再重回书架去取,再取新书。

即与其每次都从外设设备中读取,为什么不将数据放在内存中缓存起来呢,后面需要的时候直接从缓存中取。

设计原理之一:多个面向单个扇区的缓存块

课程中设计的缓存机制是设计一个缓冲池,池中包含多个缓存块,每个缓存块用于缓存任意单个扇区。

之所以是缓存任意单个扇区,而不是簇。是因为簇的大小可能很小,如1个扇区,也可能很大,比如16个扇区,而我们的课程的设计目标是希望能设计出面向小内存的系统。在一颗只有64KB内存的MCU上,如果读写的FAT32文件系统簇大小是8KB。那么刨除固件本身所需的内存,可用于支持缓存的内存就很少了,很可能还不到1个簇的大小,导致无法使用缓存。

所以,最佳的处理方面是面向单个扇区。在相同内存条件下,这样设计,相比面向簇,能让代码中所能使用的缓存块个数增多。

如果图书馆设置了一条规则,即你一次只能拿一本书到书桌去参考,桌上只能保留一本,而你要写论文时要参考很多书,怕是你肯定要疯了。现在要看A,跑去取A;接下看B,再跑去取B;发现又要看A,又去取A…..

所以,最好是允许能在桌上留多本,这样你可以一会拿A书来看下,一会又拿B书来看,再拿A来看……这样就避免了反复跑去书架取书。

设置多个缓存块,也是如此。避免了类似上述的情况。

设计原理之二:使用LRU缓存替换算法

由于内存空间有限,导致缓存池中的缓存块数量有限,所以当需要为指定扇区设定缓存时,就需要从缓存池中找出一个缓存块。这个算法就是缓存替换算法,即要用哪个现有的缓存替换成新的缓存

课程使用的是LRU算法,即最近最少使用算法。很很时间不用的缓存,我们可以假定它以后也可能继续保持长时间不用,所以选择的时候,就选择最长时间不用的。具体而方如下:

如上图所示,按使用时间排序,最近刚刚使用的位于队列开始,最长时间未使用的位于最后。每次使用了某个缓存块,立即将其移动队列头部;选择替换缓存时,选择队列尾部,因为其是最长时间没有用到的。

书桌上的空间总是有限的,取新书意味着桌上的某本书要让位。选择拿本书让位,即对应于这里的缓存替换算法。

选择最久没有打开参考的书让位,就是类似于LRU缓存替换算法。

设计原理之三:每层创建一个缓存池

这样设计的目的是提升缓存查找效率。当内存空间够大时,可为每一层增加缓存池,这样各层在自己的缓存池中读写,效率会更高。当内存空间小时,可共用同一个缓存池,效率会低一些。

当你的论文需要参考多种学科的书籍时,如果桌面空间足够大,你可以将桌面空间划分成几块区域,各区域分别用于放置不同学科的参考书。

某些学科需要参考的书较多,可以为其划分大点的空间,某些学科划分小点的空间。这样不同的空间用于不同学科书籍的“缓存”。

如此以来,各个学科书籍的缓存互不干扰。例如A学科参考的书数量不多,就那几本,但是参考的很频繁,而B学科需要参考的书数量很多,由于为A设置了专门的区域,A中的书很可能大部分时间都保留在桌面上,不受B学科书籍的影响。从整体上提升了效率。

重点难点

注意事项

其它缓存块替换算法

在操作系统原理书籍上,一般为会专门的章节讲这块知识。网上的博客也有简单的写,例如https://blog.csdn.net/moakun/article/details/80075608

常见问题

这篇文章对您有用吗?

我们要如何帮助您?

发表评论

电子邮件地址不会被公开。 必填项已用*标注