零拷贝
1️⃣ 传统 I/O 过程
在没有 DMA 技术之前,I/O 过程如下所述 (以 read 举例):
- 用户执行系统调用
read:将控制权从 用户态 转换到 内核态,此时进程阻塞在这里。 CPU向磁盘发送I/O请求:磁盘接收到I/O请求后,就需要的数据填充到自己的磁盘缓冲区,然后产生中断信号。- 磁盘向
CPU发送I/O中断信号:CPU先就把磁盘缓冲区的数据一次一个字节的读进到自己的 寄存器。- 再把 寄存器的数据 写入到 内存 中,但是传输过程中
CPU无法执行其他任务。
- 系统调用
read返回:将控制权从 内核态 转换到 用户态。

2️⃣ DMA 技术
定义:
在进行 I/O 设备和内存的数据传输的时候,数据搬运的工作全部交给 DMA 控制器,而 CPU 不再参与任何与数据搬运相关的事情,这样 CPU 就可以去处理别的事务。
- 用户执行系统调用
read:将控制权从 用户态 转换到 内核态,此时进程还是会阻塞在这里。 CPU向DMA发送I/O请求:此时CPU就可以执行其他任务,搬运工作就交给DMA。DMA再将I/O请求发送给磁盘:磁盘接收到I/O请求后,就需要的数据填充到自己的磁盘缓冲区,然后产生中断信号。- 磁盘向
DMA发送I/O中断信号:DMA将 磁盘控制器缓冲区 中的数据拷贝到 内核缓冲区 中,此时不占用CPU。
DMA再向CPU发送I/O中断信号:CPU再将 内核缓冲区 的数据拷贝到 用户缓冲区。
- 系统调用
read返回:将控制权从 内核态 转换到 用户态。

3️⃣ 传统文件传输
四次拷贝 + 四次切换
read + write: 先将磁盘上的文件读取出来,然后通过网络协议发送给客户端。

4️⃣ 零拷贝
定义:不在内存层面去拷贝数据,也就是说全程没有通过 CPU 来搬运数据,所有的数据都是通过 DMA 来进行传输的。
作用:优化文件传输的性能
目的:减少「上下文切换」和「数据拷贝」的次数。
方法:总共分为两种
方法一:mmap + write(三次拷贝 + 四次切换)
可知,在 read 系统调用时:会将 内核缓冲区 的内容拷贝到 用户缓冲区。
为了减少此处的开销,可以直接使用 mmap 代替 read ,这使得 进程 和 操作系统 共享内核缓冲区。
mmap() 会将 内核缓冲区 的内容直接 映射到 用户缓冲区,减少一次拷贝的。

方法二:sendfile(三次拷贝 + 两次切换)
sendfile 可以直接将 内核缓冲区 里的数据拷贝到 socket 缓冲区

本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 GYu的妙妙屋!
