下面是一个简单案例的快速testing:一个程序从标准input读取数字列表,并将所有数字异或。
iostream版本:
#include 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 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 指出下面的速度差异主要是由于保持与CI / Ofunction同步的iostream I / Ofunction。 我们可以通过调用std::ios::sync_with_stdio(false);来closures它std::ios::sync_with_stdio(false); :
#include 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获胜! 事实certificate,这种内部同步/刷新通常是减慢iostream I / O。 如果我们不混合cstdio和iostream,我们可以closures它,然后iostream是最快的。
代码: https : //gist.github.com/3845568
cin / cout的性能可能会很慢,因为它们需要保持与底层C库同步。 如果要使用CIO和C ++ IO,这是非常重要的。
但是,如果只打算使用C ++ IO,则只需在任何IO操作之前使用下面的行
std::ios::sync_with_stdio(false);
有关更多信息,请参阅libstdc ++文档: http : //gcc.gnu.org/onlinedocs/libstdc++/manual/io_and_c.html
可能scanf比使用stream有点快。 尽pipestream提供了很多types的安全性,并且不需要在运行时parsing格式化string,但它通常具有不需要过多的内存分配的优点(这取决于您的编译器和运行时)。 这就是说,除非性能是你唯一的最终目标,而你正处于关键的道路上,那么你应该更喜欢安全(较慢)的方法。
有一个非常好吃的文章,由Herb Sutter写的“ 庄园农场的string格式 ”,详细介绍了像sscanf和lexical_cast这样的string格式化程序的性能,以及使得它们缓慢或者快速运行的东西。 这是类似的,可能是那种会影响C风格IO和C ++风格之间的性能的东西。 与格式化程序的主要区别往往是types安全性和内存分配的数量。
我只是花了一个晚上在UVA在线(Factovisors,一个非常有趣的问题,看看)的问题上工作:
我在提交时收到了TLE(超出时间限制)。 在解决在线评判站点的这些问题上,您可能需要2-3秒的时间来处理数千个用于评估您的解决scheme的testing用例。 对于像这样的计算密集型问题,每微秒计数。
我正在使用build议的algorithm(在网站的讨论论坛上阅读),但仍然得到TLEs。
我把“cin >> n >> m”改成了“scanf(”%d%d“,&n,&m)”和几个小小的“cout”改为“printfs”,我的TLE变成了“Accepted”!
所以,是的,这可以造成很大的差别,特别是在时间限制很短的时候。
哇,谈谈过早的优化。 如果不是一个可笑的优化。 在cin >> x最大化您的quadcore CPU之前,I / O会在你的程序中cin >> x瓶颈。
好的,嗤之以鼻:不,不好的做法是将换成 。 在C ++中使用C ++库。 不要使用scanf ,不要调用malloc ,不要传递,不要收200美元。
如果您关心性能和string格式,请查看Matthew Wilson的FastFormat库。
编辑 – 链接到该图书馆的精确出版物: http : //accu.org/index.php/journals/1539
是的,iostream比cstdio慢。
是的,如果你用C ++开发,你可能不应该使用cstdio。
话虽如此,如果你不关心格式化,input安全性,等等,等等,那么有更快的方法来获取I / O比scanf …
例如,这是一个自定义例程来从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; }
有stdio实现( libio )实现FILE *作为C ++ streambuf,fprintf作为运行时格式parsing器。 IOstream不需要运行时格式parsing,这一切都是在编译时完成的。 因此,在后端共享的情况下,可以期望iostream在运行时更快。
问题是cin有很多的开销,因为它给了你一个scanf()调用之上的抽象层。 如果你正在编写C ++软件,你不应该使用scanf() ,因为这是cin目的。 如果你想要performance,你可能不会用C ++编写I / O。
#include #include #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'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; }
忘记它可能只是testing是否重要。 文件末尾有一个错误,但是这个C代码比快速的cpp版本快得多。
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
原来的CPP是30秒,这是2秒。
一般使用的语句cin和cout似乎比c ++中的scanf和printf慢,但实际上它们更快!
问题是:在C ++中,无论何时使用cin和cout ,默认情况下都会发生同步过程,以确保如果在程序中同时使用scanf和cin ,则它们将彼此同步。 此同步过程需要时间。 因此cin和cout APPEAR会变慢。
但是,如果同步过程设置为不发生,则cin比scanf快。
要跳过同步过程,请在main()的开始部分在程序中包含以下代码片段:
std::ios::sync_with_stdio(false);
访问此网站获取更多信息。
即使scanf比cin快,也没关系。 绝大多数时候,你将会从硬盘或键盘上读取数据。 获取原始数据到您的应用程序需要更多的时间比scanf或cin处理它需要更多的时间。
当然,通过iostream使用cstdio是很荒谬的。 至less当你开发软件的时候(如果你已经在使用c ++而不是c了,那就去一路使用,而不是仅仅因为缺点而受益)。
但在网上裁判你没有开发软件,你正在创build一个程序,应该能够做的事情微软软件需要60秒,在3秒内实现!
所以,在这种情况下,黄金法则就像(当然,如果你不使用java进入更麻烦)
使用c ++,并使用它的所有function(和沉重/缓慢)来解决问题
如果你有时间限制,然后改变printfs和scanfs的cins和cout(如果你使用类string搞砸了,打印如下:printf(%s,mystr.c_str());
如果你仍然有时间限制,然后尝试做一些明显的优化(例如避免太多embedded/ / / dowhiles或recursion函数)。 还要确保通过太大的引用对象传递…
如果仍然有时间限制,那么尝试更改std :: vectors并为c数组设置。
如果你仍然有时间限制,然后继续下一个问题…