【程序员不圆4】【Linux1】零拷贝简单说1

1,010 阅读2分钟

零拷贝简单说

1. 零拷贝到底指什么

一般说的零拷贝指的是从用户文件输入到用户文件输出CPU拷贝的次数为零.

要讲零拷贝就要聊一聊和其他的拷贝方式的区别

1.1 两拷贝

上面是自创的名词,是指最原始情况下要完成从用户的存储空间到用户的套接字CPU拷贝的次数为二

代码如下

read(file, tmp_buf, len);
write(socket, tmp_buf, len);

这四次拷贝分别是:

  1. 磁盘 -> 内核空间(DMA拷贝)
  2. 内核空间 -> 用户空间(CPU拷贝)
  3. 用户空间 -> 内核空间(CPU拷贝)
  4. 内核空间 -> 网卡设备(DMA拷贝)

1.2 一拷贝

一拷贝使用的是mmap() + wirte(),或者sendfile(),将用户空间映射到内核空间

代码如下

// mmap + write
mmap(tmp_buf, len, prot, flags, file_fd, offset);
write(socket, tmp_buf, len);

// sendfile
sendfile(file_fd, socket_fd, offset, len)

这三次拷贝分别是:

  1. 磁盘 -> 内核空间(DMA拷贝)
  2. 内核空间 -> 内核空间(CPU拷贝)
  3. 内核空间 -> 网卡设备(DMA拷贝)

1.3 零拷贝

1.3.1 scatter/gather

DMA分散存储,而后聚集之后传输,避免CPU拷贝

// 需要硬件支持的sendfile 
sendfile(file_fd, socket_fd, offset, len)

这两次分别是:

  1. 磁盘 -> 内核空间(DMA拷贝)
  2. 内核空间 -> 网卡设备(DMA拷贝)

1.3.2 splice()

与senfile相比,能在任意类型的输出任意类型

splice(file_fd, off_in, socket_fd, off_out, len, flags)

这两次分别是:

  1. 磁盘 -> 内核空间(DMA拷贝)
  2. 内核空间 -> 网卡设备(DMA拷贝)

1.3.2 绕过内核

1.3.2.1 用户直接访问硬件

这种技术赋予用户进程直接访问硬件设备的权限,这让用户进程能有直接读写硬件设备,在数据传输过程中只需要内核做一些虚拟内存配置相关的工作

1.3.2.2 内核控制访问硬件

内核会控制 DMA 引擎去替用户进程做缓冲区的数据传输工作

1.3.3 优化用户空间和内核空间数据传输

1.3.3.1 Copy On Write

异步写入

写入的时候才给副本,其他人都读的是一个资源,写的时候写入新的副本,占用了新的空间

1.3.3.2 缓存区共享

用多个内核缓存区代替需要放入用户空间的操作

1.4 现有零拷贝技术

使用场景 名称 系统调用 说明
Linux sendfile sendfile
Linux sendfile64 sendfile64
Linux splice splice
windows TransmitFile TransmitFile 官方称是零拷贝
Java FileChannel transferTo sendfile
远程直接内存访问(RDMA)协议 零拷贝

参考资料

https://blog.csdn.net/u013256816/article/details/52589524

https://zhuanlan.zhihu.com/p/308054212

https://zh.wikipedia.org/wiki/%E9%9B%B6%E5%A4%8D%E5%88%B6