Linux C 中的 read(2) 如何工作?
How does read(2) in Linux C work?
根据手册页,我们可以指定要从文件描述符中读取的字节数。
但是在读取的实现中,将创建多少读取请求来执行读取?
例如,如果我想读取4MB,它会只为4MB创建一个请求还是将它拆分成多个小请求?例如每个请求 4KB?
如果有可用数据,读取将 return 立即可用且适合缓冲区的数据,无需等待。如果没有可用数据,它会一直等到有可用数据,并且 return 它可以做什么,而无需等待更多。
具体多少取决于文件描述符所指的内容。如果它指的是套接字,那将是套接字缓冲区中的任何内容。如果它是一个文件,那将是缓冲区缓存中的任何内容。
当您调用 read
时,它只会发出一个请求来填充缓冲区大小,如果它无法填充所有缓冲区(没有更多数据或数据未像套接字中那样到达)它 returns 它实际写入你的缓冲区的字节数。
正如手册所说:
RETURN VALUE
Upon successful completion, these functions shall return a non-negative integer indicating the number of bytes actually read. Otherwise, the functions shall return −1 and set errno to indicate the
error.
这取决于你走多深。
C 库只是在一个 read()
系统调用中将你给它的大小直接传递给内核,所以在那个级别它只是一个请求。
在内核内部,对于标准缓冲模式下的普通文件,您请求的 4MB 将从多个页面缓存页面(每个页面 4kB)复制,这些页面不太可能是连续的。任何实际上不在页面缓存中的文件数据都必须从磁盘中读取。该文件可能不会连续存储在磁盘上,因此 4MB 可能会导致对底层块设备的多个请求。
真的没有一个正确的答案,除了无论请求最终到达什么层,无论有多少个都是必要的。通常,单个请求将传递给内核。这可能会导致不再向其他层发出请求,因为所有信息都在内存中。但是,如果必须从软件 RAID 中读取数据,则可能必须向多个物理设备发出请求才能满足请求。
我不认为你能给出比 "whatever the implementer thought was was the best way" 更好的答案。
read(2)是一个系统调用,所以它调用vDSO共享库来调度系统调用(在很早的时候它曾经是一个中断,但现在有更快的方法调度系统调用)。
在内核内部调用首先由vfs(虚拟文件系统)处理;虚拟文件系统为 inode(代表打开文件的结构)提供了一个通用接口,以及与底层文件系统交互的通用方式。
vfs 分派到底层文件系统(mount(8) 程序会告诉您存在哪个挂载点以及那里使用的文件系统)。 (有关详细信息,请参阅此处 http://www.inf.fu-berlin.de/lehre/SS01/OS/Lectures/Lecture16.pdf )
文件系统可以进行自己的缓存,因此磁盘读取次数取决于缓存中存在的内容以及文件系统如何为特定文件的存储分配块以及文件的存储方式分成磁盘块 - 所有问题都针对特定的文件系统)
如果你想做你自己的缓存然后用O_DIRECT标志打开文件;在这种情况下,努力不使用缓存;但是,所有读取都必须对齐到 512 个偏移量并且大小为 512 的倍数(这是为了您的缓冲区可以通过 DMA 传输到后备存储 http://www.quora.com/Why-does-O_DIRECT-require-I-O-to-be-512-byte-aligned)
根据手册页,我们可以指定要从文件描述符中读取的字节数。
但是在读取的实现中,将创建多少读取请求来执行读取?
例如,如果我想读取4MB,它会只为4MB创建一个请求还是将它拆分成多个小请求?例如每个请求 4KB?
如果有可用数据,读取将 return 立即可用且适合缓冲区的数据,无需等待。如果没有可用数据,它会一直等到有可用数据,并且 return 它可以做什么,而无需等待更多。
具体多少取决于文件描述符所指的内容。如果它指的是套接字,那将是套接字缓冲区中的任何内容。如果它是一个文件,那将是缓冲区缓存中的任何内容。
当您调用 read
时,它只会发出一个请求来填充缓冲区大小,如果它无法填充所有缓冲区(没有更多数据或数据未像套接字中那样到达)它 returns 它实际写入你的缓冲区的字节数。
正如手册所说:
RETURN VALUE
Upon successful completion, these functions shall return a non-negative integer indicating the number of bytes actually read. Otherwise, the functions shall return −1 and set errno to indicate the error.
这取决于你走多深。
C 库只是在一个 read()
系统调用中将你给它的大小直接传递给内核,所以在那个级别它只是一个请求。
在内核内部,对于标准缓冲模式下的普通文件,您请求的 4MB 将从多个页面缓存页面(每个页面 4kB)复制,这些页面不太可能是连续的。任何实际上不在页面缓存中的文件数据都必须从磁盘中读取。该文件可能不会连续存储在磁盘上,因此 4MB 可能会导致对底层块设备的多个请求。
真的没有一个正确的答案,除了无论请求最终到达什么层,无论有多少个都是必要的。通常,单个请求将传递给内核。这可能会导致不再向其他层发出请求,因为所有信息都在内存中。但是,如果必须从软件 RAID 中读取数据,则可能必须向多个物理设备发出请求才能满足请求。
我不认为你能给出比 "whatever the implementer thought was was the best way" 更好的答案。
read(2)是一个系统调用,所以它调用vDSO共享库来调度系统调用(在很早的时候它曾经是一个中断,但现在有更快的方法调度系统调用)。
在内核内部调用首先由vfs(虚拟文件系统)处理;虚拟文件系统为 inode(代表打开文件的结构)提供了一个通用接口,以及与底层文件系统交互的通用方式。
vfs 分派到底层文件系统(mount(8) 程序会告诉您存在哪个挂载点以及那里使用的文件系统)。 (有关详细信息,请参阅此处 http://www.inf.fu-berlin.de/lehre/SS01/OS/Lectures/Lecture16.pdf )
文件系统可以进行自己的缓存,因此磁盘读取次数取决于缓存中存在的内容以及文件系统如何为特定文件的存储分配块以及文件的存储方式分成磁盘块 - 所有问题都针对特定的文件系统)
如果你想做你自己的缓存然后用O_DIRECT标志打开文件;在这种情况下,努力不使用缓存;但是,所有读取都必须对齐到 512 个偏移量并且大小为 512 的倍数(这是为了您的缓冲区可以通过 DMA 传输到后备存储 http://www.quora.com/Why-does-O_DIRECT-require-I-O-to-be-512-byte-aligned)