0 00:00:00,000 --> 00:00:07,560 1 00:00:07,600 --> 00:00:11,520 下面我们来讨论磁盘缓存 2 00:00:11,560 --> 00:00:14,920 磁盘缓存是放在内存里的 3 00:00:14,960 --> 00:00:17,440 磁盘数据的缓存 4 00:00:17,480 --> 00:00:20,360 那这些缓存呢 是为了避免 5 00:00:20,400 --> 00:00:22,520 对同一块磁盘扇区里的内容 6 00:00:22,560 --> 00:00:27,160 进行反复引用时候的多次磁盘访问 7 00:00:27,280 --> 00:00:29,560 我们先说什么是缓存 8 00:00:29,600 --> 00:00:33,800 缓存实际上是数据传输过程当中 9 00:00:33,840 --> 00:00:36,000 双方速度差异比较大的时候 10 00:00:36,040 --> 00:00:37,720 我在中间为了匹配速度 11 00:00:37,760 --> 00:00:39,760 引入的一个中间层 12 00:00:39,800 --> 00:00:41,320 我们这里磁盘缓存呢 13 00:00:41,360 --> 00:00:43,200 就是把磁盘扇区的内容 14 00:00:43,240 --> 00:00:46,760 在内存当中做一个缓存区 15 00:00:46,800 --> 00:00:47,920 如果内存里有 16 00:00:47,960 --> 00:00:51,280 我就可以直接用内存里的缓存数据了 17 00:00:51,320 --> 00:00:53,360 在这儿我们可以看到这种做法 18 00:00:53,400 --> 00:00:56,080 和我们前面讲的虚拟存储很类似 19 00:00:56,120 --> 00:01:00,120 虚拟存储是用磁盘空间 20 00:01:00,160 --> 00:01:03,840 来存内存里存不下的这些数据 21 00:01:03,880 --> 00:01:06,400 而现在这个磁盘缓存是倒过来 22 00:01:06,440 --> 00:01:07,720 所以从这个角度来讲呢 23 00:01:07,760 --> 00:01:10,160 它们俩有很多地方是相似的 24 00:01:10,200 --> 00:01:13,480 但是它们也有很多地方是不一样的 25 00:01:13,520 --> 00:01:17,320 比如说内存和磁盘缓存 26 00:01:17,360 --> 00:01:18,840 磁盘的访问频度呢 27 00:01:18,880 --> 00:01:23,120 它是要远低于虚拟存储的访问频率的 28 00:01:23,160 --> 00:01:24,720 由于访问频率比较低 29 00:01:24,760 --> 00:01:26,240 这个算法我就会做的 30 00:01:26,280 --> 00:01:28,760 比虚拟存储会复杂 31 00:01:28,800 --> 00:01:32,360 磁盘缓存的置换算法到底怎么来做 32 00:01:32,400 --> 00:01:33,400 也就是说我到底该 33 00:01:33,440 --> 00:01:36,240 把哪些磁盘块的内容在内存里做缓存 34 00:01:36,280 --> 00:01:37,640 哪些不做 35 00:01:37,680 --> 00:01:39,400 在具体讨论 36 00:01:39,440 --> 00:01:41,920 一种磁盘缓存置换算法之前 37 00:01:41,960 --> 00:01:46,280 我们先讨论一下单缓存和双缓存 38 00:01:46,320 --> 00:01:48,240 这里单缓存和双缓存呢 39 00:01:48,280 --> 00:01:50,400 指的是这个缓存区 40 00:01:50,440 --> 00:01:52,520 到底是一个还是两个 41 00:01:52,560 --> 00:01:54,240 首先我们来看单缓存 42 00:01:54,280 --> 00:01:55,440 它的做法是什么呢 43 00:01:55,480 --> 00:01:57,080 设了一个缓存区 44 00:01:57,120 --> 00:01:58,800 然后有两头 45 00:01:58,840 --> 00:02:01,480 一头是CPU 一头是设备 46 00:02:01,520 --> 00:02:03,960 设备往这缓存区里写数据的时候呢 47 00:02:04,000 --> 00:02:05,880 由于我只有单缓存 48 00:02:05,920 --> 00:02:08,840 这时候CPU这头呢是不能操作的 49 00:02:08,880 --> 00:02:12,760 等CPU这一头能够从缓存区里 50 00:02:12,800 --> 00:02:13,960 读数据的时候 51 00:02:14,000 --> 00:02:16,320 设备这一头是不能往里写的 52 00:02:16,360 --> 00:02:17,120 大家还记得吗 53 00:02:17,160 --> 00:02:20,120 我们前面讨论到的生产者 消费者问题 54 00:02:20,160 --> 00:02:22,400 就是跟这儿是很类似的 55 00:02:22,440 --> 00:02:24,840 由于在这里我任何一个时刻 56 00:02:24,880 --> 00:02:27,800 只有一个可以对这个缓存区进行操作 57 00:02:27,840 --> 00:02:31,120 它的速度就很受限制 58 00:02:31,160 --> 00:02:33,280 如果说你两边交互频繁的话 59 00:02:33,320 --> 00:02:36,480 那这时候就有我们这里的双缓存 60 00:02:36,520 --> 00:02:39,520 它是设置两个缓存区 61 00:02:39,560 --> 00:02:41,160 在一个缓存区 62 00:02:41,200 --> 00:02:43,640 由一头在进行操作的时候 63 00:02:43,680 --> 00:02:45,240 比如说这里头I/O设备 64 00:02:45,280 --> 00:02:47,600 往缓存区1里头写数据 65 00:02:47,640 --> 00:02:49,920 那么这时候缓存区2呢 66 00:02:49,960 --> 00:02:52,640 就可以由CPU来从里读数据 67 00:02:52,680 --> 00:02:54,560 这两个是可以同时进行的 68 00:02:54,600 --> 00:02:56,840 因为它俩在不同的缓存区里头 69 00:02:56,880 --> 00:02:59,280 一旦是我写完了 这回也读空了 70 00:02:59,320 --> 00:03:01,360 它两头做一个切换 71 00:03:01,400 --> 00:03:03,960 我们两头又都可以继续进行了 72 00:03:04,000 --> 00:03:07,200 这样的话它的交换速度就会更快 73 00:03:07,240 --> 00:03:09,120 有了这个讨论之后 我们来看 74 00:03:09,160 --> 00:03:12,280 磁盘缓存的访问频率置换算法 75 00:03:12,320 --> 00:03:13,680 在这里设计这个算法 76 00:03:13,720 --> 00:03:16,080 要解决的问题是在于 77 00:03:16,120 --> 00:03:17,560 在磁盘访问的时候 78 00:03:17,600 --> 00:03:20,640 我有可能访问某一个扇区里的数据 79 00:03:20,680 --> 00:03:22,040 我频繁的访问 80 00:03:22,080 --> 00:03:26,200 这个频繁的访问如果说我们用LFU的话 81 00:03:26,240 --> 00:03:29,920 那这个计数就会很快速的增加到很大 82 00:03:29,960 --> 00:03:34,640 这时候你再往后用LFU它就不能反映 83 00:03:34,680 --> 00:03:38,800 当前你进行引用的真实情况 84 00:03:38,840 --> 00:03:40,200 我怎么来做呢 85 00:03:40,240 --> 00:03:41,640 它的思路是这样 86 00:03:41,680 --> 00:03:44,120 对于密集访问的这一段 87 00:03:44,160 --> 00:03:47,040 我不对它进行引用计数 88 00:03:47,080 --> 00:03:48,680 基本上说起来就是 89 00:03:48,720 --> 00:03:53,080 在短周期之内我用LRU 90 00:03:53,120 --> 00:03:56,960 在长周期里我用LFU 91 00:03:57,000 --> 00:03:59,440 这样的话我就可以在短周期里头 92 00:03:59,480 --> 00:04:01,960 靠特殊的栈的处理 93 00:04:02,000 --> 00:04:04,960 来描述我的访问顺序 94 00:04:05,000 --> 00:04:07,080 然后在长的时间尺度里 95 00:04:07,120 --> 00:04:12,960 我用LFU来进行访问次数的计数 96 00:04:13,000 --> 00:04:16,280 具体怎么做呢 我们来看 97 00:04:16,320 --> 00:04:21,480 这是访问频率置换算法的示意图 98 00:04:21,520 --> 00:04:24,960 首先这是LRU里的那个特殊的栈 99 00:04:25,000 --> 00:04:27,240 这是栈底 这是栈顶 100 00:04:27,280 --> 00:04:30,000 和前面的LRU不同的地方是在于 101 00:04:30,040 --> 00:04:33,280 我把这个栈分成了三段 102 00:04:33,320 --> 00:04:36,040 第一段叫新区域 103 00:04:36,080 --> 00:04:38,720 第二段叫中间区域 104 00:04:38,760 --> 00:04:41,480 然后第三段叫旧区域 105 00:04:41,520 --> 00:04:42,880 分三段的目的呢 106 00:04:42,920 --> 00:04:45,960 是为了这三段我做不同的处理 107 00:04:46,000 --> 00:04:48,800 具体这种不同的处理在什么地方呢 108 00:04:48,840 --> 00:04:50,600 每一次访问的时候 109 00:04:50,640 --> 00:04:52,760 访问某一块数据块 110 00:04:52,800 --> 00:04:55,160 那我把这一块放到这个栈顶 111 00:04:55,200 --> 00:04:59,360 这是LRU的要求 112 00:04:59,400 --> 00:05:02,440 然后我又附着上两个 113 00:05:02,480 --> 00:05:04,960 如果说你这个引用的这一块 114 00:05:05,000 --> 00:05:08,200 是在新区域里头 115 00:05:08,240 --> 00:05:09,600 它往前移的时候 116 00:05:09,640 --> 00:05:11,560 它的计数是不变的 117 00:05:11,600 --> 00:05:14,240 这就是我们真正的LRU 118 00:05:14,280 --> 00:05:16,280 如果说不是在这新区域里头 119 00:05:16,320 --> 00:05:18,760 是在中间区域或者是旧区域里头 120 00:05:18,800 --> 00:05:20,080 那么引用的时候 121 00:05:20,120 --> 00:05:22,880 不但挪过去并且把计数要加一 122 00:05:22,920 --> 00:05:25,960 那么这样一来我们就可以实现 123 00:05:26,000 --> 00:05:29,000 在新区域里头不加一 124 00:05:29,040 --> 00:05:31,400 避免了你这密集访问所带来的 125 00:05:31,440 --> 00:05:34,400 引用计数的快速增加 126 00:05:34,440 --> 00:05:38,240 而在中间区域和旧区域里头我加一 127 00:05:38,280 --> 00:05:42,760 那这是我们LFU的要求 128 00:05:42,800 --> 00:05:44,280 有了这两个之后呢 129 00:05:44,320 --> 00:05:46,880 我新加入的这些块 130 00:05:46,920 --> 00:05:49,600 我直接把它放到栈顶 131 00:05:49,640 --> 00:05:52,360 这是LRU的要求 132 00:05:52,400 --> 00:05:57,000 并且把它引用计数置为1 133 00:05:57,040 --> 00:05:59,240 然后说我淘汰的时候怎么办呢 134 00:05:59,280 --> 00:06:02,240 原来淘汰说我在这里栈底的 135 00:06:02,280 --> 00:06:07,160 现在它是在旧区域里去找计数最小的 136 00:06:07,200 --> 00:06:09,400 这是LFU的要求 137 00:06:09,440 --> 00:06:11,840 但是和LFU的区别是在于 138 00:06:11,880 --> 00:06:15,760 我不在整个栈里去找计数最小的 139 00:06:15,800 --> 00:06:17,440 有可能这个密集访问 140 00:06:17,480 --> 00:06:21,760 和中间这种新加进来的它的计数很小 141 00:06:21,800 --> 00:06:24,560 这样一来的话就定义这个中间区域 142 00:06:24,600 --> 00:06:25,840 就是为了避免 143 00:06:25,880 --> 00:06:28,720 我的计数刚进来用了没多长时间 144 00:06:28,760 --> 00:06:31,080 它正是我们频繁要使用的 145 00:06:31,120 --> 00:06:32,440 但是由于计数比较小 146 00:06:32,480 --> 00:06:35,720 你把它置换出去的这种情况 147 00:06:35,760 --> 00:06:37,680 我只是在旧区域里头 148 00:06:37,720 --> 00:06:40,520 我才按照计数大小来选 149 00:06:40,560 --> 00:06:41,840 使得这个中间区域呢 150 00:06:41,880 --> 00:06:43,200 变成是一个过渡的 151 00:06:43,240 --> 00:06:44,560 有了这样一种做法之后 152 00:06:44,600 --> 00:06:48,640 我们就把原来在虚拟存储里的算法 153 00:06:48,680 --> 00:06:50,400 改造成一个更复杂 154 00:06:50,440 --> 00:06:53,920 可以用来做磁盘缓存置换算法的 155 00:06:53,960 --> 00:06:57,520 这个访问频率置换算法 156 00:06:57,560 --> 00:07:02,040 这是磁盘缓存置换算法 157 00:07:02,080 --> 00:07:04,800 那到这儿我们就讲完了 158 00:07:04,840 --> 00:07:08,200 I/O子系统里的磁盘缓存 159 00:07:08,240 --> 00:07:11,200 我们把刚才讲过的内容总结一下 160 00:07:11,240 --> 00:07:12,560 我们在这节课里呢 161 00:07:12,600 --> 00:07:16,240 首先对I/O访问的特征进行了一个介绍 162 00:07:16,280 --> 00:07:18,600 我们有多种不同的设备 163 00:07:18,640 --> 00:07:20,440 然后这些设备的访问方式呢 164 00:07:20,480 --> 00:07:21,360 各有各的特点 165 00:07:21,400 --> 00:07:25,080 针对块设备 字符设备 166 00:07:25,120 --> 00:07:27,240 和网络设备这三种不同情况 167 00:07:27,280 --> 00:07:29,840 我们进行不同的处理 168 00:07:29,880 --> 00:07:33,240 然后数据传输我们可以分成 169 00:07:33,280 --> 00:07:37,280 轮询方式 中断方式 DMA方式 170 00:07:37,320 --> 00:07:38,760 这几种方式 171 00:07:38,800 --> 00:07:41,200 是我们在I/O子系统里常用的 172 00:07:41,240 --> 00:07:43,160 然后接下来我们介绍了 173 00:07:43,200 --> 00:07:44,760 我们常用的一种设备 174 00:07:44,800 --> 00:07:47,200 磁盘设备里头的优化 175 00:07:47,240 --> 00:07:48,800 这里面优化又分成两个 176 00:07:48,840 --> 00:07:51,080 一个是我对I/O请求 177 00:07:51,120 --> 00:07:53,080 到底我哪个先去访问 178 00:07:53,120 --> 00:07:55,720 这是磁盘调度讨论的问题 179 00:07:55,760 --> 00:07:58,000 第二个是磁盘缓存 180 00:07:58,040 --> 00:07:59,320 我把磁盘上的数据 181 00:07:59,360 --> 00:08:01,160 哪些放到内存里做缓存 182 00:08:01,200 --> 00:08:03,920 也给了一个算法 183 00:08:03,960 --> 00:08:05,760 I/O设备有很多种 184 00:08:05,800 --> 00:08:07,240 其它各种各样的设备 185 00:08:07,280 --> 00:08:11,040 也有针对各自的特点进行的一些优化 186 00:08:11,080 --> 00:08:12,400 只是由于时间的缘故 187 00:08:12,440 --> 00:08:14,880 我们在这儿没有做深入的讨论了 188 00:08:14,920 --> 00:08:16,040 那到这个地方呢 189 00:08:16,080 --> 00:08:18,680 我们这学期的课就讲完了 190 00:08:18,720 --> 00:08:19,600 好 谢谢大家 191 00:08:19,640 --> 00:08:22,840 我们这节课就上到这里 下课 192 00:08:22,880 --> 00:08:23,360 193 00:08:23,400 --> 00:08:23,440