服务器将硬盘上的文件,传给用户,需要几次拷贝?
解决这个问题,需要明白具体的工作流程是什么?
read(file, buf, len); // 把文件读到缓冲区buf中
write(socket, buf, len); // 把buf中的内容发送给用户
关于哪个步骤需要拷贝:
- 把磁盘中文件拷贝到kernel buf
- 把kernel buf拷贝到user buf
- 把user buf拷贝到socket 中的kernel buf
- 把socket buffer 拷贝到 网卡设备的buffer
其实1,2是read,3,4是write
所以说,一共拷贝4次,而且kernel mod和user mod的切换也是4次。
Linux 2.1内核开始引入了sendfile函数。省去了将操作系统的read buffer拷贝到程序的buffer,以及从程序buffer拷贝到socket buffer的步骤
而是直接将kernel buf 拷贝 到 socket buf。 实际上是把2,3两部步骤整合了。
拷贝次数
上下文切换
这里把上下文的切换次数从4次减少到2次,同时也把数据copy的次数从4次降低到了3次。
Java NIO中的FileChannal.transferTo()方法就是这样的实现,这个实现是依赖于操作系统底层的sendFile()实现的
但是,这还不是Zero-Copy。
- 将文件拷贝到kernel buffer中
- 向socket buf中写入当前要拷贝数据的位置和偏移量
-
根据socket buf中的位置和偏移量,直接将kernel buf拷贝到网卡buffer中。
这样只需要拷贝两次。这里的零拷贝是针对kernel来讲的,数据在kernel模式下是Zero-Copy。
在kafka和netty中会使用到Zero-Copy,大大提升了性能。
网友评论