【发布时间】:2014-05-28 22:02:45
【问题描述】:
我的 C++ 程序读入由换行符分隔的文本文件流。出于性能原因,我使用 C I/O 函数来处理这些数据。我正在使用fgets() 将此文本文件流的一行读入char * 缓冲区;缓冲区使用与此问题无关的其他功能进行处理。行被读入直到 EOF。
fgets() 中的幕后——例如,查看 OpenBSD 的源代码实现——看起来这个函数将重新填充 FILE 指针的内部缓冲区,一旦它用完字符来解析换行符(假设有有更多的字符需要浏览并暂时忽略其他终止条件)。
问题:通过使用gprof 进行分析,看起来很多时间都花在了读入和处理输入上,而不是程序中的其他地方,这通常是有效的。为了提高性能,我想探索减少这个程序的总 I/O 开销,我正在处理非常大(多 GB)的输入。
问题:也许最小化重新填充是将文件 I/O 降至最低的一种方法。是否有(与平台无关的)方法来调整FILE 指针使用的内部缓冲区的大小,或者我需要用我自己的缓冲区编写一个自定义的fgets() 类函数?在解析文本文件时,是否有其他策略可以降低总体 I/O 开销(查找、读取等)?
注意:我很抱歉,但我没有说明我正在使用哪种流 - 我应该更清楚地说明我的应用程序从 stdin(标准输入)以及常规文件中读取.
【问题讨论】:
-
出于性能原因,您说您使用的是
fgets()而不是 C++ 的std::getline()。您是否测量过性能并发现它很重要?我的猜测是,仅读取数据的不可避免的开销将支配使用不同输入函数所获得的任何节省。但这只是一个猜测。 -
如果适合您的情况,您可以使用操作系统功能,例如
mmap -
@MattMcNabb:我有一个建议
mmap的答案(现已删除),但 OP 澄清说这是不合适的,因为需要从stdin读取。 -
@MattMcNabb:我没有看到
mmap与串行读取文件相比有多大改进。正如 Greg Hewgill 现在已删除的答案中的评论所说,mmap可以帮助以不那么线性的方式访问文件。 -
fgets的主要问题是额外的数据副本。如果您不需要以 NUL 结尾的字符串,则可以通过一次直接读取对齐的 8k 缓冲区并自己查找换行符来加快速度。您未指定的字符串处理可能只使用换行符而不是 NUL 作为终止符;否则,我建议使用strchr而不是手动逐字节搜索; glibc 实现将在 64 位架构上一次搜索 8 个字节,这明显快于逐字节循环。 YMMV。 (并且一如既往地提防过早的优化。)