mmap 文件映射 通常情况下,我们可以使用read()
和write()
去访问文件,除此之外,Linux 还提供了mmap()
系统调用,它可以将文件映射到进程的地址空间,这样程序就可以通过访问内存的方式去访问文件了。那么与read()
和write()
相比,使用mmap()
去访问文件能带来什么好处呢?
使用mmap()
一个明显的好处就是减少一次 I/O 拷贝,譬如说,当我们使用read()
读取文件时,通常的做法是这样:
char buffer[SIZE];
ssize_t n = read(fd, buffer, SIZE);
这个过程实际上发生了两次 I/O 拷贝,第一次是将磁盘中的文件内容拷贝到 OS 的文件系统缓冲区,第二次是将 OS 缓冲区的数据拷贝到用户缓冲区。而使用
mmap()
读取文件时,只会发生第一次拷贝操作,也就是将文件内容拷贝到 OS 文件系统缓冲区,完成这个拷贝操作之后,mmap()
还会执行其它一些复杂的操作,例如将相应的 OS 缓冲区映射到进程的地址空间。尽管
mmap()
可以减少一次 I/O 拷贝,但由于mmap()
的实现很复杂,调用mmap()
将会带来额外的开销,因此在一些情况下,没有使用mmap()
的必要:- 访问小文件时,直接使用
read()
或write()
将更加高效。 - 单个进程对文件执行顺序访问时(sequential access),使用
mmap()
几乎不会带来性能上的提升。譬如说,使用read()
顺序读取文件时,文件系统会使用 read-ahead 的方式提前将文件内容缓存到文件系统的缓冲区,因此使用read()
将很大程度上可以命中缓存。
mmap()
去访问文件会更高效呢?- 对文件执行随机访问时,如果使用
read()
或write()
,则意味着较低的 cache 命中率。这种情况下使用mmap()
通常将更高效。 - 多个进程同时访问同一个文件时(无论是顺序访问还是随机访问),如果使用
mmap()
,那么 OS 缓冲区的文件内容可以在多个进程之间共享,从操作系统角度来看,使用mmap()
可以大大节省内存。
read(fd, buffer, len);
write(sockfd, buffer, len);
文章图片
正如我们前面说到的,使用
read()
读取文件时,将发生两次 I/O 拷贝。然而,数据发送的过程也发生了两次 I/O 拷贝,第一次是write()
将用户缓冲区的数据写入内核的 socket 发送缓冲区,成功写入之后write()
会返回,在write()
返回之后,内核会将 socket 发送缓冲区的数据拷贝到网卡驱动。可以看到,整个过程发生了四次 I/O 拷贝操作。然而除了考虑 I/O 拷贝带来的开销,我们还要考虑系统 context switch 带来的开销,当程序调用
read()
时,系统会从用户态切换到内核态,而当read()
返回时,又会导致系统从内核态切换到用户态,所以调用read()
发生两次 context switch,同理,调用write()
也会发生两次 context switch。Linux 提供了
sendfile()
用来减少我们前面提到的 I/O 拷贝和 context switch 的次数:sendfile(sockfd, fd, NULL, len);
使用
sendfile()
发送文件时,实际发生了三次 I/O 拷贝,第一次是将磁盘中的文件内容拷贝到 OS 的文件系统缓冲区,第二次是将 OS 缓冲区的数据拷贝到 socket 的发送缓冲区,最后一次是将 socket 发送缓冲区的数据发送到网卡驱动。可以看到,与使用read()
和write()
发送文件相比,使用sendfile()
减少了一次 I/O 拷贝和两次 context switch。如果使用的网卡支持 scatter-gather 特性,那么还可以再减少一次 I/O 拷贝:
【C|浅谈 Linux 的 Zero Copy 技术】
文章图片
这种情况下,使用
sendfile()
发送文件只会发生两次 I/O 拷贝,第一次是将磁盘中的文件拷贝到 OS 的文件系统缓冲区,而第二次是将 OS 缓冲区的数据直接拷贝到网卡驱动。可以使用下面的命令查看网卡是否支持 scatter-gather 特性:$ ethtool -k eth0 | grep scatter-gather
scatter-gather: on
tx-scatter-gather: on
tx-scatter-gather-fraglist: off [fixed]
转自:
http://senlinzhan.github.io/2017/03/25/%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B%E4%B8%AD%E7%9A%84zerocpoy%E6%8A%80%E6%9C%AF/
推荐阅读
- Linux|109 个实用 shell 脚本
- linux笔记|linux 常用命令汇总(面向面试)
- Linux|Linux--网络基础
- linux|apt update和apt upgrade命令 - 有什么区别()
- c/c++|有感 Visual Studio 2015 RTM 简介 - 八年后回归 Dot Net,终于迎来了 Mvc 时代,盼走了 Web 窗体时代...
- linux|2022年云原生趋势
- C/C++|C/C++ basis 02
- Go|Docker后端部署详解(Go+Nginx)
- 开源生态|GPL、MIT、Apache...开发者如何选择开源协议(一文讲清根本区别)