每次读/写有多少次随机/顺序访问

How many random / sequential access per fread / fwrite?

本文关键字:随机 顺序 访问 多少次      更新时间:2023-10-16

我有以下关于C文件I/o的问题。

在物理级别(硬盘驱动器),假设每个fread(n_blocks, size, length,FILE fp)操作应该花费1次随机访问第一页(块)和n-1次顺序访问同一缓冲区的下一个块是有效的吗?

我认为这是因为操作系统有如此多的进程,几乎可以肯定其中一个进程也在本地程序的每个fread之间写入或读取文件,并且通过这种假设硬盘驱动器位于另一个扇区/圆柱体。

可以这样假设吗?

无论你是否这样认为,这都是对现实的过度简化。

第一件事:你似乎认为第三个参数(length)对应于一些离散的"访问操作"的数量。事实并非如此。fread所做的只是读取size*length字节;因此,下面三个调用做完全相同的事情,只要乘法不溢出:

fread(n_blocks, size, length, fp);
fread(n_blocks, size*length, 1, fp);
fread(n_blocks, 1, size*length, fp);
实际上发生的是,fread/fwrite将从进程内存中的内部缓冲区读写。该缓冲区可以通过setbuf/setvbuf函数进行控制。当缓冲区满/空时,它们将把读/写转发给操作系统,该操作系统有自己的文件缓存。如果您正在读取并且操作系统无法在缓存中找到文件的部分,那么您的程序将等待,直到实际从驱动器中获取数据。当写入时,数据将被复制到操作系统缓存中并驻留在那里,直到操作系统决定将其写入驱动器,这可能发生在您的程序关闭文件并存在很久之后。反过来,今天的硬盘有自己的内部缓存,操作系统甚至可能不知道。

对于所有实际目的,您不应该关心每个fread/fwrite调用访问多少驱动器。只要知道C、操作系统和底层硬件将尽其所能以最快的速度提供所请求的数据。但是,请记住,整个堆栈是为顺序访问优化的。因此,请避免在没有充分理由的情况下使用fseek在文件周围跳跃。

不,它不是。如果文件系统是碎片化的,单个文件的块可能会分散在整个硬盘上。

不,不是。您甚至不能假设fread将触发物理I/O。你的操作系统有可能对I/O请求做很多事情,包括缓存结果、重新排序和合并(或分割)读(甚至有时写)。

如果有很多I/O正在进行,你也不能指望得到顺序读取,这取决于你使用的缓冲区大小(可能还有I/O流库)。一些操作系统提供了一些方法来"提示"您将按顺序读取文件描述符(或mmap ed区域),这可能会有所帮助。

从应用程序程序员的角度来看,读取数据块的确切过程是不确定的。这一切都归结为磁盘调度器,它组织来自多个进程的多个请求同时进行的访问操作。有多种算法可以解决这个问题,但过于简单的思考(1次随机搜索,n次顺序搜索)是不现实的。最后,C标准和c++标准都没有明确地定义这样的事情。

正如许多人解释的那样,必须考虑缓存(可能在几个级别上)。

也许你想知道如何从C代码中加速或调整它。这是高度特定于操作系统的

在最近的Linux系统上,您可以使用readahead, madvise(与mmap一起使用)和其他系统调用。

通常,您可以简单地提前读取文件(可能只是使用cat yourfile > /dev/null),然后您的程序将在Linux上运行得更快。

尝试在一些大文件上运行两次wc单词计数实用程序。第二次运行通常比第一次运行快得多。