我不知道这是不是真的,但是当我在一个提供问题的网站上阅读常见问题解答时,我发现了一些东西,引起了我的注意:
检查您的输入/输出方法。在C ++中,使用cin和cout太慢。使用这些,您将保证无法用大量输入或输出解决任何问题。请改用printf和scanf。
有人可以澄清一下吗?在C ++程序中使用scanf()真的比使用cin >>更快吗?如果是,那么在C ++程序中使用它是否是一个好习惯?我以为这是C特定的,尽管我只是在学习C ++。
我不知道这是不是真的,但是当我在一个提供问题的网站上阅读常见问题解答时,我发现了一些东西,引起了我的注意:
检查您的输入/输出方法。在C ++中,使用cin和cout太慢。使用这些,您将保证无法用大量输入或输出解决任何问题。请改用printf和scanf。
有人可以澄清一下吗?在C ++程序中使用scanf()真的比使用cin >>更快吗?如果是,那么在C ++程序中使用它是否是一个好习惯?我以为这是C特定的,尽管我只是在学习C ++。
Answers:
这是对一个简单案例的快速测试:一个从标准输入中读取数字列表并对所有数字进行XOR的程序。
iostream版本:
#include <iostream>
int main(int argc, char **argv) {
int parity = 0;
int x;
while (std::cin >> x)
parity ^= x;
std::cout << parity << std::endl;
return 0;
}
scanf版本:
#include <stdio.h>
int main(int argc, char **argv) {
int parity = 0;
int x;
while (1 == scanf("%d", &x))
parity ^= x;
printf("%d\n", parity);
return 0;
}
结果
使用第三个程序,我生成了一个文本文件,其中包含33,280,276个随机数。执行时间为:
iostream version: 24.3 seconds
scanf version: 6.4 seconds
更改编译器的优化设置似乎并没有太大改变结果。
因此:确实存在速度差异。
编辑:用户Clyfish 指出,速度差异主要归因于iostream I / O功能与CI / O功能保持同步。我们可以通过调用来关闭此功能std::ios::sync_with_stdio(false);
:
#include <iostream>
int main(int argc, char **argv) {
int parity = 0;
int x;
std::ios::sync_with_stdio(false);
while (std::cin >> x)
parity ^= x;
std::cout << parity << std::endl;
return 0;
}
新结果:
iostream version: 21.9 seconds
scanf version: 6.8 seconds
iostream with sync_with_stdio(false): 5.5 seconds
C ++ iostream胜了! 事实证明,这种内部同步/刷新通常会使iostream I / O变慢。如果我们不混合使用stdio和iostream,则可以将其关闭,然后iostream最快。
iostream
在一次scanf
调用中解析多个整数时丢失。
http://www.quora.com/Is-cin-cout-slower-than-scanf-printf/answer/Aditya-Vishwakarma
cin
/的性能cout
可能很慢,因为它们需要与基础C库保持同步。如果要同时使用C IO和C ++ IO,这是必不可少的。
但是,如果仅打算使用C ++ IO,则只需在执行任何IO操作之前使用以下行。
std::ios::sync_with_stdio(false);
有关更多信息,请参见相应的libstdc ++文档。
可能scanf比使用流更快。尽管流提供了很多类型安全性,并且不必在运行时解析格式字符串,但它通常具有不需要过多内存分配的优点(这取决于编译器和运行时)。就是说,除非性能是您唯一的最终目标并且您处于关键位置,否则您应该真正偏爱更安全(较慢)的方法。
Herb Sutter在这里写了一篇非常美味的文章“ 庄园农场的字符串格式化程序 ”,他详细介绍了字符串格式化程序的性能,sscanf
以及lexical_cast
使它们缓慢或快速运行的原因是什么。这有点类似,很可能会影响C风格的IO和C ++风格之间的性能。与格式化程序的主要区别在于类型安全性和内存分配数量。
我只是花了一个晚上在UVa Online上解决问题(Factovisors,一个非常有趣的问题,请检查一下):
我的投稿获得TLE(超过时间限制)。在这些解决问题的在线法官站点上,您有大约2-3秒的时间限制,以处理可能用于评估解决方案的数千个测试用例。对于像这样的计算密集型问题,每微秒都至关重要。
我正在使用建议的算法(在该站点的讨论论坛中了解到),但仍获得TLE。
我只将“ cin >> n >> m”更改为“ scanf(“%d%d”,&n,&m)”,将一些小的“ couts”更改为“ printfs”,我的TLE变成了“ Accepted”!
因此,是的,它可以带来很大的不同,尤其是在时间限制较短时。
如果您同时关注性能和字符串格式,请查看Matthew Wilson的FastFormat库。
编辑-链接到该库上的Accu出版物:http : //accu.org/index.php/journals/1539
是的,iostream比cstdio慢。
是的,如果您使用C ++开发,则可能不应该使用cstdio。
话虽如此,如果您不关心格式,类型安全,等等,等等,等等,还有比scanf更快的获取I / O的方法...
例如,这是一个自定义例程,用于从STDIN获取数字:
inline int get_number()
{
int c;
int n = 0;
while ((c = getchar_unlocked()) >= '0' && c <= '9')
{
// n = 10 * n + (c - '0');
n = (n << 3) + ( n << 1 ) + c - '0';
}
return n;
}
问题在于cin
涉及很多开销,因为它在scanf()
调用之上为您提供了一个抽象层。你不应该使用scanf()
过cin
,如果你正在写C ++软件,因为这是想cin
是。如果您想提高性能,您可能根本不会用C ++编写I / O。
cin
真的比“抽象”(在运行时)scanf
?我不这么认为... scanf
必须在运行时解释格式字符串,而iostream
在编译时就知道格式。
std::istream
在运行时如何配置(通过I / O操纵器或通过在istream
对象本身上设置标志)。一FILE*
对另一方面对象有没有这样的状态,所以一个电话scanf
在这方面更稳定。
语句cin
和cout
一般用法似乎比C ++ scanf
和慢printf
,但实际上它们更快!
关键是:在C ++中,每当您使用cin
和时cout
,默认情况下都会进行一个同步过程,以确保如果在程序中同时使用scanf
和cin
,则它们两者将彼此同步。此同步过程需要时间。因此cin
,cout
出现速度较慢。
但是,如果将同步过程设置为不发生,cin
则速度比快scanf
。
要跳过同步过程,请在以下代码的开头,在程序中包含以下代码段main()
:
std::ios::sync_with_stdio(false);
访问此站点以获取更多信息。
#include <stdio.h>
#include <unistd.h>
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
static int scanuint(unsigned int* x)
{
char c;
*x = 0;
do
{
c = getchar_unlocked();
if (unlikely(c==EOF)) return 1;
} while(c<'0' || c>'9');
do
{
//*x = (*x<<3)+(*x<<1) + c - '0';
*x = 10 * (*x) + c - '0';
c = getchar_unlocked();
if (unlikely(c==EOF)) return 1;
} while ((c>='0' && c<='9'));
return 0;
}
int main(int argc, char **argv) {
int parity = 0;
unsigned int x;
while (1 != (scanuint(&x))) {
parity ^= x;
}
parity ^=x;
printf("%d\n", parity);
return 0;
}
文件末尾有一个错误,但是此C代码比更快的C ++版本快得多。
paradox@scorpion 3845568-78602a3f95902f3f3ac63b6beecaa9719e28a6d6 ▶ make test
time ./xor-c < rand.txt
360589110
real 0m11,336s
user 0m11,157s
sys 0m0,179s
time ./xor2-c < rand.txt
360589110
real 0m2,104s
user 0m1,959s
sys 0m0,144s
time ./xor-cpp < rand.txt
360589110
real 0m29,948s
user 0m29,809s
sys 0m0,140s
time ./xor-cpp-noflush < rand.txt
360589110
real 0m7,604s
user 0m7,480s
sys 0m0,123s
原始的C ++花了30秒,C代码花了2秒。
当然,在iostream上使用cstdio是荒谬的。至少当您开发软件时(如果您已经在c之上使用c ++,那么请一路使用并利用它的好处,而不是仅仅因为它的缺点而受苦)。
但是在线判断您不是在开发软件,而是在创建一个程序,该程序应该能够在3秒钟内完成Microsoft软件的工作,而这需要60秒钟才能完成!!!
因此,在这种情况下,黄金法则就像(当然,如果您不使用Java陷入更多麻烦)
即使scanf
比快cin
,也没关系。在绝大多数情况下,您将在硬盘或键盘上进行阅读。获取原始数据到你的应用需要数量级更多的时间比它采取scanf
或cin
对其进行处理。
iostream
是不是硬盘慢。是的,太烂了。