以较小、更频繁的读取或较大的读取方式读取输入

Reading inputs in smaller, more frequent reads or one larger read

本文关键字:读取 方式 输入      更新时间:2023-10-16

我正在做一个C++教程练习,要求计算文件中的单词数。它让我思考阅读输入的最有效的方法。一次读取整个文件的效率比读取小块(逐行或逐字符(的效率高多少?

答案会根据您执行I/O的方式而变化。

如果您使用的是POSIX open/read/close系列,一次读取一个字节将非常痛苦,因为每个字节将花费一次系统调用。

如果您使用的是C fopen/fread/fclose系列或C++iostream库,一次读取一个字节仍然不是很好,但效果要好得多。这些库保留一个内部缓冲区,并且只在read耗尽时调用它。然而,由于您正在为每个字节做一些非常琐碎的事情,每次调用的开销仍然可能使您实际必须进行的每个字节的处理相形见绌。

另一种选择是简单地mmap整个文件,然后对其进行逻辑运算。您可能注意到,也可能没有注意到,带有和不带有MAP_POPULATE标志的mmap之间存在性能差异。同样,你必须测量它然后再看。

I/O最有效的方法是保持数据流动。

也就是说,读取一个512个字符的块比512个1个字符的读取快。您的系统可能已经进行了优化,例如缓存,以加快读取速度,但您仍然有所有这些函数调用的开销。

有不同的方法来保持I/O的流动:

  • 内存映射文件I/O
  • 双重缓冲
  • 特定于平台的API

一些简单的实验应该足以证明。

创建一个1兆字节的矢量或数组
启动计时器
重复1000次:
使用1条读取指令将数据读取到容器中
结束计时器。

重复,使用for循环,读取1000000个字符,每个字符有1条读取指令。

比较您的数据。

详细信息
对于来自硬盘驱动器的每个请求,将执行以下步骤(取决于平台优化(:

  • 开始硬盘旋转
  • 读取文件系统目录
  • 在目录中搜索文件名
  • 获取请求字节的逻辑位置
  • 寻找给定的轨道&行业
  • 将一个或多个扇区的数据读入硬盘
  • 将请求的硬盘驱动器内存部分返回到平台
  • 降低硬盘驱动器的速度

这称为开销(读取扇区的情况除外(。目标是在硬盘旋转时获得尽可能多的数据传输。启动硬盘驱动器所花费的时间比保持其旋转所需的时间还要长。