C++ 为什么read()比getc()慢
为什么syscall read()比getc()函数慢C++ 为什么read()比getc()慢,c++,c,linux,unix,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) {
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()系统调用,那么为什么较慢呢?read()
涉及到上下文切换到内核,这相对较慢。当您直接使用它并一次读取一个字节时,您有许多上下文开关。但是当您使用getc()
时,它将调用read()
一次,持续4或8 kB,然后从中返回字符,而不进行进一步的上下文切换,直到耗尽缓冲区
如果将read()
与更大的缓冲区一起使用,它将比getc()
更快,因为标准C库的通用缓冲有一些开销
(编辑)注意,对于所有常用的存储介质,只能在512字节的块中读取磁盘。所以内核中必须有一些缓冲。而且由于内存是以4096字节的页面分配的,所以大多数系统(Linux肯定会这样做)对物理存储的每个请求至少读取这么多的内存。但是上下文切换也很昂贵,因此userland中额外的缓冲层仍然可以节省大量时间。这种缓冲用于所有的libc IO,它包括使用文件*
的所有内容(缓冲区是文件
结构的一部分),因此fread()
对于小型读取将比read()
更快。回答#1:它并不慢
答案2:视情况而定
您不希望对从文件中读取的每个字节进行系统调用(包括内存保护系统上的上下文切换)。在第一个字节大小的访问中,您会将适当数量的数据(比如4k)读入内存,并将第一个字节提供给调用者。在后续字节大小的读取中,您根本不需要调用内核或实际访问文件;您只需从缓冲区传递下一个字节,直到必须读取另一个4k块为止
默认情况下,标准C库的调用(fread()
,fgets()
,fgets()
等)就是这样做的。您可以选中BUFSIZ
以获取默认缓冲区大小。您可以通过setvbuf()
调用更改缓冲区大小或完全禁用缓冲
read()
不是标准C库的一部分,它是一个POSIX系统调用。基本上,它是POSIX系统上标准C库调用的后端。(在Windows系统上,fgetc()
将调用Win32 API。)因此,read()
不缓冲,为字节大小的块调用它效率非常低。如果调用read()
,通常这样做是因为您希望自己进行缓冲
一般来说,不要混合使用POSIX和标准库I/O调用。使用POSIX API进行低级访问,使用标准库进行便携方便(以及良好的默认性能)。您是如何确定它的速度较慢的?因为在包含7 878 999个字符(字节)的getc()代码的文件中,不使用缓冲区可以以3倍的速度工作faster@NatKup缓冲区是存储字符的临时位置。假设您的缓冲区有1000个字符,那么对getc的第一个调用读取1000个字符并用它们填充缓冲区。接下来对getc的999调用不进行任何读取,它们只从缓冲区中获取一个字符,因此速度非常快。然后,对getc的第1001次调用将再次填充缓冲区,因此它会重复。