操作系统——零拷贝

操作系统——零拷贝

参考:https://www.cnblogs.com/gunduzi/p/13537862.html

1、什么是零拷贝?

  • 零拷贝主要指优化拷贝,将 CPU Copy 减少为 0,因为拷贝过程很耗 CPU 时间,所以尽量把这个时间减小,引入 DMA 作为 CPU 的一个代理,可以让 CPU 去做别的事情,因为像磁盘这样的设备性能太差,如果让 CPU 直接访问,那就太浪费了。

那什么是 CPU Copy?什么是 DMA 呢?

  • CPU copy:拷贝过程需要 CPU 参与
  • DMA copy:拷贝过程交给 DMA ,CPU 不用管,DMA 如同 CPU 的代理。
  • DMA:操作系统访问磁盘的方式之一。

2、为什么要使用零拷贝?

(通过两个样例来解释零拷贝的出现)

2.1、 传统文件读访问(写类似)

过程如下:

  • ① 进程向操作系统发起 read 系统调用,进行上下文切换,切换到内核态,需要将磁盘数据读入内存,自己进行阻塞状态。
  • ② 操作系统向磁盘发起请求,磁盘将数据导入磁盘驱动缓冲区,无需使用 CPU,当驱动器缓冲区满了之后,向操作系统发起中断请求,告诉操作系统自己的缓冲区已满。
  • ③ 操作系统将驱动缓冲区的数据拷贝到内核缓冲区,此步骤为 DMA copy。
  • ④ 如果内核中的数据少于用户请求数据,重复步骤②和③,直到数据满足要求为止。
  • ⑤ 将数据从内核缓冲区拷贝到用户缓冲区,此过程为 CPU copy,同时从系统调用中返回,进行上下文调用,切换到用户态。

该过程,需要2次上下文切换3 次 copy(磁盘拷贝到驱动缓冲区,驱动缓冲区拷贝到内核缓冲区,内核缓冲区拷贝到用户缓冲区)。

在这里插入图片描述

DMA 工作过程:

  • ① 进程向操作系统发起 read 系统调用,进行上下文切换,切换到内核态,需要将磁盘数据读入内存,自身进程进入阻塞状态;
  • ② CPU 收到之后,将请求交给 DMA,自己去忙其他事情;
  • ③ DMA 向磁盘发起请求;
  • ④ 磁盘将数据读到磁盘驱动器缓存区中,当缓冲区数据满了之后,向操作系统发起中断请求;
  • ⑤ DMA 将缓冲区的数据复制到内核缓冲区中;
  • ⑥ 如果数据少于用户请求数据,重复④⑤,直到数据达到请求位置,此时 DMA 向操作系统发起中断请求;
  • ⑦ CPU 将内核缓冲区的数据拷贝到用户缓冲区。

DMA 类似 CPU 的一个代理,与磁盘进行交互,因为磁盘速度太慢,CPU 直接和磁盘交互太浪费 CPU 时间。

传统文件访问总结:

  • ① 内核缓冲区拷贝到用户缓冲区,整个过程仅为拷贝且需要 CPU 参加,若数据量很大,则浪费 CPU 时间。
  • ② 在内存中保存两份数据,也浪费空间。

零拷贝想优化的地方: 能否将 “内核缓冲区拷贝到用户缓冲区” 过程避免,在内存中只留一份数据,让用户空间和内核空间共享(注:磁盘拷贝到内存是不可避免的)。即尽量减少拷贝的次数

2.2、发送数据到网络

过程如下:

  • ① 将磁盘数据通过 DMA 拷贝到内核缓冲区(中间会经过磁盘驱动缓冲区);
  • ② CPU 将内核缓冲区数据拷贝到用户缓冲区;
  • ③ CPU 将用户缓冲区数据拷贝到socket 缓冲区
  • ④ DMA 将 socket 缓冲区数据拷贝到网卡。

该过程,发生了4 次上下文切换4 次拷贝。4 次上下文切换:① 用户空间发起read系统调用,从用户态切换为内核态;② 数据准备好后,从内核态把数据拷贝到用户态;③ 把数据从用户缓冲区拷贝到内核socket缓冲区;④ 发送完后,重新进入用户态正常执行

在这里插入图片描述

发送数据到网络总结: ①第二次拷贝和第三次拷贝好像什么也没做,就是转了一个圈。
零拷贝想优化的地方: 能否将第二次和第三次拷贝优化,直接将数据从内核缓冲区拷贝到网卡呢。(自然是可以的,使用操作系统提供的接口,如 Linux 的 sendfile)

3、零拷贝的几种方法

  • mmap:文件拷贝到内存(内核缓冲区),多个进程可以访问(不用从内核缓冲区拷贝到自己的用户缓冲区)。
  • sendfile:文件拷贝到 socket 缓冲区。
  • splice:任意两个文件描述符之间互相通信(如从一个 sockek 缓冲区拷贝到另一个 socket 缓冲区等)。
3.1、内存映射文件(Memory Mapped Files,mmap)

1、概念把磁盘上的一个文件通过 DMA 拷贝到内存,然后对内存文件的操作就像直接操作磁盘文件一样。由于文件在内存中以页的方式存储,当有些页被修改之后,需要把脏页刷新回磁盘,这时不需要像传统的方式发起 write 系统调用,这时可以直接将内存中的脏页刷新回磁盘,无需 CPU 参加,无需上下文切换。
2、mmap 具体流程

  • ① 进程启动映射过程,并在虚拟地址空间创建映射区域;
  • ② 调用 系统调用函数 mmap,实现虚拟地址空间和物理地址空间的映射;
  • ③ 进程发起对映射空间的访问,引发缺页中断,将磁盘上的数据拷贝到内存中。

注:

  • 在第③步使用这一页数据时(read/write操作),才会把磁盘上的数据通过DMA 将磁盘数据拷贝到内核缓冲区。
  • 在第②步处于用户空间的进程直接将虚拟地址空间映射到内核缓冲区,无需将处于内核的数据拷贝到用户进程。(即,多个进程可访问内核缓冲区的数据,而不需要将内核缓存区数据拷贝到自己的缓冲区中)。

处于内核空间的缓冲区可以被映射到多个进程,也就是说多个进程可以通过共享内存,而无需在内存中保存多份重复数据,多个进程共享数据的过程如下:

  • 进程A读取某一页数据,发现内存中没有,引发缺页中断,DMA将磁盘数据拷贝到内存。
  • 进程B也需要同一页的数据,引发缺页中断,这时并不会再去磁盘读取,而是直接将虚拟地址空间映射到进程A刚刚访问的物理地址空间上。

mmap 缺点:若对磁盘进行随机读写,速度还是慢,顺序读写还行。写到 mmap 的数据并没有刷到磁盘,在程序主动调用 flush 的时候,操作系统才会把缓冲区的数据刷到磁盘。

3.2、sendfile(0次CPU拷贝)

针对 2.2 中的发送数据到网络,可以通过 sendfile 系统调用解决
在这里插入图片描述
在 Linux 2.1 版本中,去掉了 “内核缓冲区到用户缓冲区的拷贝”;在 Linux 2.4 版本中,又去掉了 “内核缓冲区到socket缓冲区的拷贝”,内核缓冲区和socket缓冲区之间仅单向拷贝 传输文件描述符数据是直接从内核缓冲区拷贝到网卡的

文件描述符:内核利用文件描述符来访问文件。文件描述符是非负整数,打开现存文件或新建文件时,内核会返回一个文件描述符。读写文件也需要使用文件描述符来指定待读写的文件。

3.3、splice

Linux 2.6 新增了一个新的系统调用 splice。
sendfile 和 splice区别

  • sendfile:只能将数据从文件拷贝到别的缓冲区,如把文件拷贝到socket缓冲区,而不能从一个socket 缓冲区拷贝到另一个socket缓冲区或别的场景。
  • splice:适用于任意两个文件描述符之间互相通信。通过管道实现,两个缓冲区中间连接一个管道,但是并不是把第一个缓冲区的数据拷贝到 pipe,而是将指针(引用)拷贝进去。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值