我需要编写一个程序,它会在输出文件中写入许多字符。
我的程序还需要编写换行符以便更好地格式化。
我理解ofstream
是一个缓冲流,如果我们为文件io使用缓冲流,我们就会获得性能。但是,如果我们使用std::endl
,则会刷新输出,并且由于缓冲输出,我们将失去任何潜在的性能增益。
我想如果我将'\n'
用于新行,则只有在std::endl
时才会刷新输出。它是否正确?是否有任何技巧可用于在文件输出期间获得性能增益?
注意:我想在文件写入操作完成时刷新缓冲输出。我认为通过这种方式,我可以最小化文件I / O,从而获得性能。
答案 0 :(得分:18)
通常,如果需要最大性能,流类的用户不应该弄乱流的刷新:当流满时,流会在内部刷新缓冲区。这实际上比等待所有输出都准备好更有效,特别是对于大文件:缓冲数据在仍然可能在内存中时写入。如果您创建一个巨大的缓冲区,并且只有在虚拟内存系统将部分数据放入光盘而不是文件时才写入。需要从光盘读取并再次写入。
与std::endl
相关的要点是,人们滥用它会导致缓冲区刷新,并且他们不知道性能影响。 std::endl
的意图是人们可以控制在合理的点上刷新文件。为了使其有效,他们需要知道他们在做什么。可悲的是,有太多的人不知道std::endl
做了什么宣传它作为一个行结尾的用途,以至于在很多地方使用它是完全错误的。
也就是说,以下是您可能希望尝试提高性能的一些事项。我假设你需要格式化输出(使用std::ofstream::write()
不会给你)。
std::endl
。如果编写代码已经存在并且在许多地方使用std::endl
,其中一些可能在您无法控制的地方,则可以使用过滤流缓冲区,该缓冲区使用其大小合理的内部缓冲区,并且不会将调用转发给其{ {1}}函数到底层流缓冲区。虽然这涉及一个额外的副本,但这比一些虚假的冲洗更好,因为这些是更高的数量级。sync()
产生影响,但调用std::ofstream
曾经影响某些实现的性能。如果这会产生影响,您可能希望使用不同的IOstream实现,因为在性能方面可能存在更多错误。std::ios_base::sync_with_stdio(false)
调用std::locale
时使用std::codecvt<...>
返回true
的{{1}}。使用always_noconv()
可以轻松检查这一点。您可以使用std::use_facet<std::codecvt<char, char, stdd::mbstate_t> >(out.get_loc()).always_noconv()
来获取std::locale("C")
,这应该是真的。std::locale
方面的默认实现仍可能执行您不需要的操作。特别是如果您的数字格式相当简单,即您没有继续更改格式标记,您没有替换字符映射(即您不使用有趣的std::num_put<char>
方面)等等。这可能是合理的使用自定义std::ctype<char>
方面:为整数类型创建一个快速但简单的格式化函数并为内部不使用std::num_put<char>
的浮点创建一个良好的格式化函数相当容易。有些人建议使用内存映射文件,但这只有在预先知道目标文件的大小时才有效。如果是这种情况,这是一种提高性能的好方法,否则就不值得了。请注意,您可以通过创建使用内存映射接口的自定义snprintf()
来将流格式化与内存映射文件(或更常见地,使用任何类型的输出接口)一起使用。我发现内存映射在与std::streambuf
s一起使用时有时会有效。在许多情况下,差异并不重要。
很久以前我编写了自己的IOStreams和locales实现,它没有遇到上面提到的一些性能问题(可以从my site获得,但它有点陈旧,我还没有触及它已经近10年了)。有很多事情可以通过这个实现来改进,但我没有最新的实现,我准备在某处发布。很快,希望 - 这是我近10年来一直在想的事情,但是......
答案 1 :(得分:3)
打印\n
时不会(必须)刷新输出,而打印std::endl
或std::flush
则会。
如果你想要快速写作并且在完成任务之前不关心数据是否存在,那么用\n
完成所有写作并且不要担心(从{{3}开始)也将刷新流。)
如果您仍未获得所需的性能,可以使用closing the file - 它可以让您以任何大小的块读取数据(尝试更大的块,看看是否有帮助)。
答案 2 :(得分:0)
是的,endl
会刷新流。不要将它用于大文件。
还要确保设置 流缓冲区 。当没有设置缓冲区时,至少MSVC实现将 1个字符一次复制到filebuf
(参见streambuf::xsputn
)。这可能会使您的应用程序受CPU限制,从而导致I / O速率降低。
因此,在编写代码之前,请在代码中添加类似的内容:
char buf[256 * 1024];
mystream.rdbuf()->pubsetbuf(buf, sizeof(buf));
注意:您可以找到完整的示例应用程序here。