我在试着解决InterviewStreet上的一个问题。过了一段时间后,我确定我实际上花费了大部分时间来阅读输入。这个特定的问题有很多输入,所以这是有意义的。不合理的是为什么不同的输入方法会有如此不同的性能:
最初我有:
std::string command;
std::cin >> command;替换它会让它变得更快:
char command[5];
cin.ignore();
cin.read(command, 5);重写所有内容以使用scanf使其速度更快
char command;
scanf("get_%c", &command);总而言之,我将阅读输入的时间减少了大约1/3。
我想知道这些不同的方法在性能上有这么大的差异。此外,我想知道为什么使用gprof没有突出我在I/O上花费的时间,而是似乎将责任指向我的算法。
发布于 2012-02-02 00:07:27
这些例程有很大的差异,因为控制台输入速度几乎不重要。
而且在它需要的地方(Unix shell),代码是用C语言编写的,直接从标准输入设备读取,而且效率很高。
发布于 2012-02-02 00:32:47
冒着被否决的风险,I/O流通常比它们的C对应物更慢、更大。这不是避免在许多目的中使用它们的理由,因为它们更安全(曾经遇到过scanf或printf错误吗?不是很友好)和更通用的(例如:重载插入操作符,允许您输出用户定义的类型)。但我也要说,这不是在对性能非常关键的代码中教条式地使用它们的理由。
不过,我确实发现结果有点令人惊讶。在你列出的三个中,我怀疑这是最快的:
char command[5];
cin.ignore();
cin.read(command, 5);原因:不需要内存分配,直接读取字符缓冲区。下面的C示例也是如此,但是调用scanf来重复读取单个字符也不是最优的,即使在概念级别上也是如此,因为scanf必须解析每次传入的格式字符串。我会对你的I/O代码的细节感兴趣,因为当scanf调用读取单个字符被证明是最快的时候,发生错误的可能性是合理的。我只是想问一下,并没有冒犯的意思,但是代码真的编译并链接了优化吗?
现在来看你的第一个例子:
std::string command;
std::cin >> command;我们可以预期这会比最优的慢得多,因为你正在使用一个可变大小的容器(std::string),这将不得不涉及到一些堆分配来读取所需的缓冲区。当涉及到堆栈与堆的问题时,堆栈总是要快得多,所以如果您可以预测在特定情况下所需的最大缓冲区大小,堆栈上的一个简单的字符缓冲区将击败std::string进行输入(即使您使用了reserve)。这同样适用于堆栈上的数组,而不是std::vector,但这些容器最适合于无法预先预测大小的情况。其中std::string可能更快的情况是,人们可能会尝试重复调用strlen,而存储和维护一个size变量会更好。
至于gprof的细节,它应该强调这些问题。您是否正在查看完整的调用图,而不是平面配置文件?当然,在这种情况下,扁平轮廓可能会产生误导。我必须了解更多关于如何使用gprof的细节才能给出更好的答案。
发布于 2012-02-02 05:37:02
gprof仅在CPU时间内采样,而不在阻塞时间内采样。因此,一个程序可能花一个小时做I/O,花一个微秒做计算和gprof will only see the microsecond。
由于某些原因,这一点并不为人所知。
https://stackoverflow.com/questions/9099058
复制相似问题