为什么read()比getc()慢

时间:2013-04-22 11:24:33

标签: c++ c linux unix

为什么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()系统调用,为什么慢?

2 个答案:

答案 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进行低级访问,使用标准库以提高便携性(以及良好的默认性能)。