C write还是printf,哪个更快?

C write还是printf,哪个更快?,c,performance,unix,io,system-calls,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" ) ); } (i=0;i

执行以下测试后:

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" ) );
}
(i=0;i<3000000;i++)的
{
printf(“测试字符串\n”);
}
对于(i=0;i<3000000;i++){
写入(STDOUT_FILENO,“测试字符串”,strlen(“测试字符串”);
}
结果表明,对printf的调用总共需要3秒,而对write的调用则需要46秒。有了
printf
所具有的所有奇特的格式化魔法,以及
printf
本身调用
write
,这怎么可能呢?有什么我遗漏的吗


感谢您的任何想法和输入。

您不是在对苹果进行比较,因为
write
的循环会运行
strlen
<3000000次,而
printf
不会执行任何操作;它也不做任何格式化,所以“奇特的格式化魔法”几乎不适用

size_t len = strlen( "Test string\n" );
for( i = 0; i < 3000000; i++ ) {
    write( STDOUT_FILENO, "Test string\n", len );
}
size\u t len=strlen(“测试字符串”);
对于(i=0;i<3000000;i++){
写入(标准输出文件号,“测试字符串”,len);
}
另一个重要的区别是,
printf
每次通过
\n
时都会刷新,而
write
则不会。您应该从两个字符串中删除
\n
,以使基准测试更加公平

如何,与。。。printf本身调用write,这可能吗?有什么我遗漏的吗

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

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

如果stdout指向终端设备,则每次看到
\n
--在您的情况下,每次调用它时,
printf
都会调用
write
。如果stdout指向文件(或
/dev/null
),则
printf
仅在其内部缓冲区已满时调用write

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

除了对
write
调用较少的影响之外,还有对
write
调用的大小。硬盘中的存储量是一个扇区,通常为512字节。要写入的数据量小于扇区,可能需要读取扇区中的原始数据,对其进行修改,然后将结果写回。但是,使用完整扇区调用
write
,可能会更快,因为您不必读入原始数据
printf
的缓冲区大小被选择为典型扇区大小的倍数。这样系统可以最有效地将数据写入磁盘


我希望你的第一圈比第二圈快得多。

真的吗?您每次都在计算字符串长度,然后将其作为计时的一部分进行测量?@K-ballo经过优化,在编译过程中只应计算一次。您的输出是发送到控制台还是发送到文件?如果是控制台,那么它的成本将淹没一切。@MikeDunlavey甚至将stdout重定向到一个文件make
write
需要相当长的时间,而
printf
的速度非常快。然而,重定向到
/dev/null
,两者都很快。然后,
write
需要更少的用户时间,但是更多的系统时间和更长的时间,但是时间是相同的数量级(Linux x86_64,gcc-4.5.1)。
put
应该更快。在我的系统上,gcc-4.5.1在编译时评估
strlen
,即使没有优化。冲洗/缓冲似乎是造成差异的原因。@Danielfisher谢谢!很高兴知道,
gcc
足够聪明,可以将
strlen
表达式折叠成一个常量。
printf
不会在每个
\n
上刷新,如果输出重定向到文件。另外,更准确的说法是,
write
每次刷新,不包含任何内容——毕竟,在这个上下文中,“flush”只意味着“calls
write
”@dasblinkenlight指出,要将以null结尾的字符串复制到目的地,必须计算其长度,或者一个字符一个字符地复制。@ChrisStratton但是当您一个字符一个字符地输出一个字符串时,您仍然只能从内存中读取每个字符一次,而不是两次。
write
printf
都需要将字符串中的所有字符移动到I/O系统拥有和管理的内存中的某个位置,这些字符最终从该位置进入磁盘或tty(我有意避免使用“缓冲区”一词)<当到达
\0
字符时,code>printf将停止<当传入的计数用完时,code>write将停止。这很好地解释了一切。非常感谢。关于您对数据大小的评论…为什么不需要读取原始数据,因为它完全适合该行业?write调用是否仍然需要知道需要写入的数据?