为什么syscall read()比getc()函数慢?
for (;;) {
chr++;
amr=read(file1, &wc1, 1);
amr2=read(file2, &wc2, 1);
if (wc1 == wc2) {
if (wc1 == '\n')
line++;
if (amr == 0) {
if (eflg)
return (1);
return (0);
}
continue;
}
慢于
for (;;) {
chr++;
c1 = getc(file1);
c2 = getc(file2);
if (c1 == c2) {
if (c1 == '\n')
line++;
if (c1 == EOF) {
if (eflg)
return (1);
return (0);
}
continue;
}
当getc()调用它时使用read()系统调用,为什么慢?
答案 0 :(得分:13)
read()
涉及到内核的上下文切换,这相对较慢。直接使用它并一次读取一个字节时,您有许多上下文切换。但是当你使用getc()
时,它会调用read()
一次为4或8 kB而不是在没有进一步上下文切换的情况下从中返回字符,直到它耗尽缓冲区。
如果你使用read()
更大的缓冲区,它会比getc()
更快,因为标准C库的通用缓冲有一些开销。
(编辑)请注意,对于所有常用存储介质,只能以512字节的块读取磁盘。所以无论如何都必须在内核中进行一些缓冲。并且因为内存以4096字节的页面分配,所以大多数系统(Linux肯定会)在每次请求物理存储时读取至少那么多。但是上下文切换也很昂贵,因此用户空间中的额外缓冲层仍然可以节省大量时间。此缓冲用于所有libc IO,其中包含使用FILE*
的所有内容(缓冲区是FILE
结构的一部分),因此fread()
对于小read()
将比{{1}}更快读取。
答案 1 :(得分:2)
答案#1:它并不慢。
答案#2:这取决于。
您不希望为从文件中读取的每个字节进行系统调用(包括受内存保护的系统上的上下文切换)。在第一个字节大小的访问中,您将在内存中读取适当数量的数据(比如4k),并将第一个字节提供给调用者。在随后的字节大小的读取中,您不必调用内核或实际访问该文件;你只需从缓冲区传递下一个字节,直到你必须读取另一个4k块。
这是默认情况下标准C库的调用(fread()
,fgetc()
,fgets()
等)。您可以检查BUFSIZ
以获取默认缓冲区大小。您可以通过setvbuf()
调用更改缓冲区大小或完全禁用缓冲。
read()
不是标准C库的一部分,它是一个POSIX系统调用。基本上,它是POSIX系统上标准C库调用的后端。 (在Windows系统上,fgetc()
会调用Win32 API。)因此,read()
不缓冲,并且调用字节大小的块是低效的。如果你打电话给read()
,你通常会这样做,因为你想自己做缓冲。
一般来说,不要混用POSIX和标准库I / O调用。使用POSIX API进行低级访问,使用标准库以提高便携性(以及良好的默认性能)。