📜  Cin-Cout与Scanf-Printf

📅  最后修改于: 2021-05-30 10:09:49             🧑  作者: Mango

当输入量很大并且从stdin读取这样的输入的任务可能会成为瓶颈时,常规的竞争性程序员会面临共同的挑战。该问题伴随着“警告:大的I / O数据”。

让我们创建一个虚拟输入文件,该文件包含一个包含16个字节的行,后跟一个换行符,并具有1000000个这样的行,使文件大小为17MB应该足够了。

// Creating a dummy file of size 17 MB to compare 
// performance of scanf() and cin()
$ yes 1111111111111111 | head -1000000 > tmp/dummy

让我们通过使用scanf()与cin比较从stdin读取文件所花费的时间(使用重定向将文件从磁盘获取到stdin)。

// Filename : cin_test.cc to test the 
// We redirect above created temp file 
// of 17 MB to stdin when this program 
// is run.
#include
using namespace std;
  
int main()
{
    char buffer[256];
    while (cin >> buffer)
    {
    }
    return 0;
}

当伪文件被重定向到标准输入时,上述程序的输出。

$ g++ cin_test.cc –o cin_test
$ time ./cin_test < /tmp/dummy
real     0m2.162s
user     0m1.696s
sys     0m0.332s
// Filename : scanf_test.c to see
// performance of scanf()
// We redirect above created temp file
// of 17 MB to stdin when this program
// is run.
#include
#include
int main()
{
    char buffer[256];
    while (scanf("%s", buffer) != EOF)
    {
    }
    return 0;
}

当伪文件被重定向到标准输入时,上述程序的输出。

$ g++ scanf_test.cc –o scanf_test
$ time ./scanf_test < /tmp/dummy
real     0m0.426s
user     0m0.248s
sys     0m0.084s

好吧,以上结果与我们的观察结果一致。

为什么scanf比cin快?
从较高的角度来看,它们两者都是read()系统调用的包装,只是语法糖。唯一可见的区别是scanf()必须显式声明输入类型,而cin使用模板重载了重定向操作。这似乎不足以使性能达到5倍。

事实证明, iostream使用stdio的缓冲系统。因此, cin浪费了自己与底层C库的stdio缓冲区进行同步的时间,因此可以交错调用scanf()cin。

好消息是libstdC++提供了一个选项,可以使用以下命令关闭所有iostream标准流与其对应的标准C流的同步:

std::ios::sync_with_stdio(false);

cin的速度比scanf()快了。

有关竞争性编程中快速输入输出的详细文章

// Filename : cin_test_2.cc to see
// performance of cin() with stdio syc
// disabled using sync_with_stdio(false).
#include
using namespace std;
  
int main()
{
    char buffer[256];
    ios_base::sync_with_stdio(false);
  
    while (cin >> buffer)
    {
  
    }
    return 0;
}

运行程序:

$ g++ cin_test_2.cc –o cin_test_2
$ time./cin_test_2 
  • 像所有事物一样,这里有一个警告。关闭同步后,同时使用cinscanf()会导致未定义的混乱。
  • 关闭同步后,以上结果表明cin比scanf()快8-10%。这可能是因为scanf()在运行时解释了格式参数,并使用了可变数量的参数,而cin在编译时这样做了。

现在想知道,它能完成多快?

// Redirecting contents of dummy file to null
// device (a special device that discards the
// information written to it) using command line.
$time cat /tmp/dummy > /dev/null
real   0m0.185s
user   0m0.000s
sys    0m0.092s

哇!这太快了!!!

如果您希望与行业专家一起参加现场课程,请参阅《 Geeks现场课程》和《 Geeks现场课程美国》。