我sendfile(2)最近正在阅读,手册页指出:
Run Code Online (Sandbox Code Playgroud)sendfile() copies data between one file descriptor and another. Because this copying is done within the kernel, sendfile() is more efficient than the combination of read(2) and write(2), which would require transferring data to and from user space.
这让我想到,为什么read()/的组合write()更慢?手册页侧重于必须在用户空间之间进行的额外复制,而不是所需的总调用次数。我简短地查看了用于读写的内核代码,但没有看到副本。
为什么副本首先存在?内核不能在write()不首先将整个内容复制到内核空间的情况下从传递的缓冲区中读取吗?
异步 IO 接口如 AIO 和io_uring? 他们也抄袭吗?
为什么
read()/的组合write()更慢?
手册页对此非常清楚。做read()然后write()需要复制数据两次。
为什么副本首先存在?
应该很明显:由于您调用了read,您希望将数据复制到进程内存中指定的目标缓冲区中。同样适用于write:您希望从进程的内存中复制数据。内核并不真正知道您只想执行read+ write,并且可以避免来回复制两次。
执行时read,内核将数据从文件描述符复制到进程内存中。执行时write数据由内核从进程内存复制到文件描述符。
内核不能在
write()不首先将整个内容复制到内核空间的情况下从传递的缓冲区中读取吗?
这里的关键点是,当您读取或写入文件时,内核必须将文件从磁盘映射到内存,以便读取或写入。这称为内存映射文件 I/O,它是现代操作系统性能的一个重要因素。
文件内容已经存在于内核内存中,映射为内存页(或更多)。在 a 的情况下read,数据需要从该文件内核内存页复制到进程内存,而在 a 的情况下write,数据需要从进程内存复制到文件内核内存页。然后内核将确保在需要时(如果需要)将与文件对应的内核内存页面中的数据正确写回磁盘。
可以避免这种“中间”内核映射,将文件直接映射到用户空间内存中,但随后应用程序必须手动管理它,既复杂又容易搞砸。这就是为什么,对于正常的文件操作,文件被映射到内核内存中。内核为用户空间程序提供高级 API 以与它们交互,而繁重的工作留给内核本身。
该sendfile系统调用是更快,因为你不需要执行复制两次,但只有一次。假设你想要做一个sendfileof 文件A到文件B,那么所有内核需要做的就是从Ato复制数据B。但是,在read+的情况下write,内核需要首先复制 fromA到您的进程,然后从您的进程复制到B. 这种双拷贝当然更慢,如果你真的不需要读取或操作数据,那完全是在浪费时间。
我简短地查看了用于读写的内核代码,但没有看到副本。
就内核代码而言,读取文件的整个过程非常复杂,但内核最终做的是一个memcpy()名为的“特殊”版本copy_to_user(),它将文件内容从内核内存复制到用户空间内存(在执行实际复制之前进行适当的检查)。更具体地说,对于文件,使用了该copyout()函数,但行为非常相似,最终都调用raw_copy_to_user()(这取决于体系结构)。
异步 IO 接口如 AIO 和
io_uring? 他们也抄袭吗?
aio_{read,write}由 POSIX 定义的libc 函数只是围绕read和的异步包装器write(即它们仍在使用read和write隐藏)。这些仍然将数据复制到用户空间/从用户空间复制数据。
io_uring可以提供零拷贝操作,当使用O_DIRECT标志时open(参见手册页):
Run Code Online (Sandbox Code Playgroud)O_DIRECT (since Linux 2.4.10) Try to minimize cache effects of the I/O to and from this file. In general this will degrade performance, but it is useful in special situations, such as when applications do their own caching. File I/O is done directly to/from user- space buffers. The O_DIRECT flag on its own makes an effort to transfer data synchronously, but does not give the guarantees of the O_SYNC flag that data and necessary metadata are transferred. To guarantee synchronous I/O, O_SYNC must be used in addition to O_DIRECT. See NOTES below for further discussion.
但是,这应该小心完成,因为如果用户空间应用程序没有自行进行适当的缓存(如果需要),它很可能会降低性能。
另请参阅有关异步 I/O 的相关详细答案以及有关io_uring.
| 归档时间: |
|
| 查看次数: |
474 次 |
| 最近记录: |