我想读取 GB 量级的文件(比如 10 GB)。在 C 中读取此类文件的最快方法是什么。我正在尝试实现,tail
但我认为 I/O 可能是一个瓶颈。欢迎任何建议。
3 回答
首先:我还没有看到一台通用计算机,其物理 IO 速度足以容纳比使用的任何缓存大得多的文件,CPU 密集型处理是瓶颈。也就是说,我还没有看到所有通用计算机都存在。
因此,您必须平衡 CPU 周期优化与其他因素,例如可移植性、可维护性和可读性。我怀疑大多数用例,包括你给出的那个,都会在很大程度上指向简单地使用你的运行时库函数,相信那些作者非常了解他们在做什么。
您将希望使用低级read
系统调用来处理大文件,而不是更通用但也更高开销fread
。(可以stdio.h
用于您需要发出的相对少量的输出。)
您将希望使用lseek
跳过大部分文件,然后以块的形式向后扫描以查找行边界。
我会避免mmap
这个应用程序;它可能会在内核中触发无用的 I/O 启发式方法,并且会增加一大堆您不需要的可移植性问题。
如果这还不足以让您继续前进,请将您遇到的具体地方发布为新问题。
正如其他人所说,没有适用于所有环境的通用答案。你能做的最好的就是对许多替代品进行基准测试。
然而,有几件事可能会解释你得到的结果:
重叠的计算和读取操作:现代机器具有直接内存访问 (DMA) 硬件和总线架构,当您处理先前读取的缓冲区时,可以将数据从磁盘流式传输到一个或多个缓冲区。这个想法是运行尽可能多的并行流,以保持所有设备接口和总线以满负荷运行,否则 CPU 会因处理而最大化(而不是如下所述的无用复制),或者 - 在完美的世界中 - 两者兼而有之。例如,看Windows Overlapped IO
缓冲:磁盘 I/O 硬件和驱动程序、文件系统、内核/用户空间边界、语言 I/O API 和您自己的应用程序代码都是可以缓冲数据的地方。在一个实例中,当使用标准 C 库进行文本 I/O 时,我能够识别 PC 中的 4 级缓冲/缓存。这使得每个字节不可避免地被复制至少 4 次。寓意是,当你知道你正在按顺序访问一个巨大的流时,以原始形式(例如,没有用 \r\n 替换 \n),并且你的应用程序是机器应该做的所有事情运行,然后那些缓冲层变得几乎无用。通过使用较低级别的接口可以消除的越多,你就会走得越快。低级Windows IO API至少消除了所有用户空间的缓冲和复制。
磁盘通道性能和并行性:如果文件存储在多个磁盘上,例如使用 RAID,并且接口具有单独的 DMA 通道,则操作系统和/或您的代码可以从并行硬件中受益。同样,因为您得到您所支付的,并非所有的磁盘接口都是平等的。这是一个深奥的话题,但总的来说,服务器针对磁盘并行性和高吞吐量进行了优化。任何处理非常大文件的应用程序在服务器硬件上的运行速度都可能比在普通 PC 上更快,并且将有更多机会利用异步/重叠 IO。