写或打印,哪个更快?

时间:2012-06-26 17:44:36

标签: c performance unix io system-calls

完成以下测试后:

for( i = 0; i < 3000000; i++ ) {
    printf( "Test string\n" );
}

for( i = 0; i < 3000000; i++ ) {
    write( STDOUT_FILENO, "Test string\n", strlen( "Test string\n" ) );
}

事实证明,对printf的调用总共需要3秒钟,而写入调用需要花费46秒。如果有printf所做的所有花哨的格式魔术,以及printf本身调用write的事实,这可能吗?有什么东西我不见了吗?

赞赏任何想法和意见。

2 个答案:

答案 0 :(得分:27)

  

如何,以及... printf本身调用write的事实,这可能吗?有什么东西我不见了吗?

是的,有些东西你不见了。 printf不一定每次都会调用write 。相反,printf缓冲其输出。也就是说,它通常将其结果存储在内存缓冲区中,仅在缓冲区已满时调用write,或者在其他条件下调用。{/ p>

write是一个相当昂贵的调用,比将数据复制到printf的缓冲区要昂贵得多,因此减少write调用的数量可以获得净效果。

如果您的标准输出被定向到终端设备,那么printf每次看到write时都会调用\n - 在您的情况下,每次调用它时。如果你的stdout被定向到一个文件(或/dev/null),那么printf只在内部缓冲区已满时调用write。

假设您正在重定向输出,并且printf的内部缓冲区是4K字节,则第一个循环调用write 3000000 /(4096/12)== 8780次。但是,第二个循环调用write 3000000次。

除了write的通话次数减少之外,write的调用的大小。硬盘中的存储量是一个扇区 - 通常是512字节。写入比扇区少的数据可能涉及读取扇区中的原始数据,修改它,并将结果写回。但是,为完整扇区调用write可能会更快,因为您不必读取原始数据。 printf的缓冲区大小选择为典型扇区大小的倍数。这样,系统可以最有效地将数据写入磁盘。

我希望你的第一个循环比第二个循环快得多。

答案 1 :(得分:4)

你不是在比较苹果和苹果,因为write的循环运行strlen 3000000次,而printf不执行任何操作;它也没有做任何格式化,所以“奇特的格式魔术”几乎不适用。

size_t len = strlen( "Test string\n" );
for( i = 0; i < 3000000; i++ ) {
    write( STDOUT_FILENO, "Test string\n", len );
}

另一个重要区别是每次通过printf\n都会刷新,而write则不会。您应该从两个字符串中删除\n,以使您的基准更加公平。