C++ C++;输入性能

C++ C++;输入性能,c++,performance,profiling,iostream,stdio,C++,Performance,Profiling,Iostream,Stdio,我正试图解决面试街上的一个问题。一段时间后,我确定我实际上花了大部分时间阅读输入。这个特殊的问题有很多输入,所以这有一定的意义。不合理的是,为什么不同的输入方法具有如此不同的性能: 最初我有: std::string command; std::cin >> command; 更换后速度明显加快: char command[5]; cin.ignore(); cin.read(command, 5); 使用scanf重写所有内容使其速度更快 char command; scanf

我正试图解决面试街上的一个问题。一段时间后,我确定我实际上花了大部分时间阅读输入。这个特殊的问题有很多输入,所以这有一定的意义。不合理的是,为什么不同的输入方法具有如此不同的性能:

最初我有:

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上花费的时间,而似乎将责任归咎于我的算法。

这些例程有很大的变化,因为控制台输入速度几乎不重要


在它使用的地方(unixshell),代码是用C编写的,直接从stdin设备读取,而且效率很高

尽管有被否决的风险,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,而存储和维护大小变量会更好


至于gprof的细节,它应该强调这些问题。您是否在查看完整的调用图,而不是平面配置文件?在这种情况下,平面轮廓自然会产生误导。我必须知道一些关于如何使用gprof给出更好答案的更多细节。

gprof仅在CPU时间内采样,而不是在阻塞时间内采样。 因此,一个程序可能会花一个小时做I/O,一微秒做计算,然后


由于某些原因,这一点并不广为人知。

默认情况下,标准iostreams配置为与C stdio库一起工作-实际上,这意味着使用
cin
cout
进行交互输入和输出以外的操作往往速度较慢

要使用
cin
cout
获得良好的性能,需要禁用与stdio的同步。对于高性能输入,您甚至可能想要解开流

有关更多详细信息,请参阅以下stackoverflow问题


<> P> < /P>我觉得特别有趣的是我如何读C++的一本书(是C++圣经)吗?理论上的IoFoIP如何比STDIO函数快,因为它使用虚拟函数而不是像%s%s%d那样解析文本,但是实际上它的速度慢了10X-20X。我把这一点列在那里,理论上认为Java实际上比C快,因为虚拟机可以动态地分析代码。@satuon:我个人觉得iostream很可怕。各种级别的间接指令和非直观界面令人难以置信。IoSt流的问题是它的保存,可以追溯到C++的早期,其中模板和异常仍在研究中。所以你有一些半生不熟的解决方案,因为“向后兼容”的原因而被冻结。唉。所以基本上,iostream的实现很差,因为没有人将其用于高性能IO?@WinstonEwert-它被认为是为了设计的灵活性和优雅。虽然在实践中,它可能不会被任何人选择,因为没有人使用它!gprof对于识别CPU受限进程中的瓶颈很好(但不是很好)。识别I/O绑定进程中的瓶颈是不好的(真的,真的不好!)。@David:《gprof》的作者谈到了这一点,但当然,谁读过这些东西?每个人都认为它是一个查找瓶颈的工具,但他们没有这样的主张。
stdio
例程在其历史记录中有大量的优化,以及辅助性能优化调用,如
setvbuf()
。即使从概念上看
scanf()
似乎很复杂,也要看看任何实现:该字符串解析代码非常快。@wallyk:true,但即使是最快的字符串解析,在他的示例中也是按字符进行的!这是一个相当令人惊讶的是,char buf[n];cin.read(buf,n);会慢得多(事实上令人惊讶的是它不会快,但iostreams是一个非常大的容量)