提供相同的程序,该程序读取随机生成的输入文件并回显相同的字符串,然后将其读取到输出.唯一的区别是,在一边,我提供的读取和写入从Linux系统调用的方法,并在另一边我用FREAD/FWRITE.
使用大小为10Mb的输入来定时我的应用程序并将其回显到/ dev/null,并确保文件没有被缓存,我发现当使用非常小的缓冲区时,libc的fwrite速度更快(1个字节)案件).
这是我的时间输出,使用fwrite:
real 0m0.948s
user 0m0.780s
sys 0m0.012s
Run Code Online (Sandbox Code Playgroud)
并使用syscall写:
real 0m8.607s
user 0m0.972s
sys 0m7.624s
Run Code Online (Sandbox Code Playgroud)
我能想到的唯一可能性是内部libc已经缓冲了我的输入......不幸的是我无法在网络上找到那么多信息,所以也许这里的大师可以帮助我.
Mat*_*lin 35
使用大小为10Mb的输入对应用程序进行定时并将其回显到/ dev/null,并确保文件未缓存,我发现当使用非常小的缓冲区时,libc的frwite速度更快(1个字节)案件).
fwrite适用于缓冲的流.因此,许多小缓冲区将更快,因为它不会运行昂贵的系统调用,直到缓冲区填满(或您冲洗它或关闭流).另一方面,发送到的小缓冲区write将为每个缓冲区运行一个代价高昂的系统调用- 这就是你失去速度的地方.使用1024字节的流缓冲区,并写入1字节的缓冲区,你会看到write每千字节的 1024个fwrite调用,而不是1024个调用变为一个write- 看到差异?
对于大缓冲区,差异会很小,因为缓冲会更少,因此在fwrite和之间的系统调用数量会更加一致write.
换句话说,fwrite(3)它只是一个库例程,它将输出收集到块中,然后调用write(2).现在write(2),是一个系统调用其陷入内核.这就是I/O实际发生的地方.简单地调用内核有一些开销,然后有时间实际编写内容.如果你使用大缓冲区,你会发现它write(2)更快,因为它最终必须被调用,如果你每fwrite写一次或多次,那么fwrite缓冲开销只是:更多的开销.
如果您想了解更多相关信息,可以查看本文档,该文档解释了标准I/O流.
Dig*_*oss 15
write(2)是基本的内核操作.
fwrite(3)是一个库函数,它在write(2)之上添加缓冲.
对于小的(例如,一次一行)字节计数,fwrite(3)更快,因为仅仅进行内核调用的开销.
对于大(块I/O)字节计数,write(2)更快,因为它不打扰缓冲,你必须在两种情况下调用内核.
如果你看源cp(1),你将看不到任何缓冲.
最后,最后一个考虑因素是:ISO C vs Posix.缓冲的库函数fwrite在ISO C中指定,而内核调用如writePosix.虽然许多系统声称Posix兼容性,特别是在试图获得政府合同的资格时,实际上它特定于类Unix系统.因此,缓冲的操作更便携.因此,Linux cp肯定会使用,write但必须跨平台工作的C程序可能必须使用fwrite.
dmi*_*gov 11
您还可以使用setbuf()函数禁用缓冲.当禁用缓冲时,如果不慢,fwrite()将与write()一样慢.
有关此主题的更多信息,请访问:http://www.gnu.org/s/libc/manual/html_node/Controlling-Buffering.html