AkiraZheng's Time.

文件描述符

Word count: 771Reading time: 2 min
2024/05/18

一、内核缓冲区Page Cache

进程在调用write函数写入文件描述符时,其实不是直接写入文件,而是

  • 中段到内核空间
  • 然后再由内核空间写入内核缓冲区Page Cache(因为内核缓冲区相较于磁盘I/O速度更快)
  • 最后内核会在适当的时机将内核缓冲区的内容写入磁盘

通过这种机制,可以减少操作磁盘I/O的次数,提高磁盘I/O效率(当然也可以通过mmap函数将文件映射到内存中,这样就可以直接操作内存,内存中的操作既快速,又不用经过内核态<–>用户态的切换,更加高效)

如果想立即将内核缓冲区的内容写入磁盘,可以调用fsync函数(调用fflush函数也会将缓冲区的内容强制写入磁盘,而不等待缓冲区满再刷新)

二、零拷贝技术:mmap

磁盘相对于计算机中的CPU、内存来说,属于慢速设备,因此针对磁盘的优化,有我们上述讲到的通过内核态中的缓冲区Page Cache减少I/O访问次数,还有通过零拷贝技术来减少数据在内核态和用户态之间的拷贝次数

如果通过中断的方式,当我们发生系统调用read时,内核会将磁盘中的数据拷贝到内核缓冲区(第一次拷贝),然后再将内核缓冲区的数据拷贝到用户缓冲区,这样就发生了两次拷贝

也就是说在大量数据拷贝过程都需要CPU参与搬运,这样会浪费CPU资源,降低效率

因此进一步可以通过DMA直接内存访问技术进行优化:

  • 在不占用CPU资源的情况下(此时CPU可以执行其它任务),将数据从磁盘拷贝到内核缓冲区

  • 当DMA读取了足够多的数据,再通知CPU将数据从内核缓冲区拷贝到用户缓冲区,这样就只发生了一次拷贝

即使采用DMA技术,还是需要通过CPU进行一次拷贝,具体通过readwrite的流程如下所示(各发生2次用户态<–>内核态的上下文切换,一次切换需要耗时几十纳秒到几微秒;以及各发生一次DMA拷贝+一次CPU拷贝):

而实际上,多次拷贝是没必要的,我们可以通过mmap函数将文件映射到内存中,使readwrite直接操作共享的内核缓冲区,这样就可以减少一次拷贝,具体流程如下:

参考:什么是零拷贝?

三、I/O多路复用技术

在文章WebServer学习3:socket编程与epoll实现I/O复用中已经有详细介绍,这里不再赘述

四、事件驱动模型

在文章WebServer学习4:并发事件驱动模式Reactor和Proactor中已经有详细介绍,这里不再赘述

CATALOG
  1. 一、内核缓冲区Page Cache
  2. 二、零拷贝技术:mmap
  3. 三、I/O多路复用技术
  4. 四、事件驱动模型