![为什么 read() 比 getc() 慢?](https://linux22.com/image/31357/%E4%B8%BA%E4%BB%80%E4%B9%88%20read()%20%E6%AF%94%20getc()%20%E6%85%A2%EF%BC%9F%20.png)
为什么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
系统调用,为什么会慢呢?
答案1
由于 getc() 在返回读取的数据之前对其进行缓冲,因此对 的调用getc()
不一定会导致对read()
.read()
是一个系统调用,它比普通函数调用需要更长的时间来完成,因为内核有更多的操作要做。当你进入内核空间时,它会更改你的堆栈,保存所有上下文,处理要屏蔽的中断,而在另一端,当它完成时,它会恢复上下文,中断,将你的用户空间堆栈放回去。这就是为什么 getc() 是首选的原因,因为如果您已经有可用的缓冲数据,它可以节省大量开销。
答案2
归根结底,磁盘读取是面向块的:要从磁盘读取单个字节,硬件最终会读取一个字节块(512 或 1024 或某个数量),缓冲所有这些,并将其传递给内核。如果您从文件的块 0 读取文件的字节 0,做一些工作,然后从文件读取字节 1,内核最终可能会再次读取文件的块 0。再次针对字节 2,再次针对字节 3。是的,在内核和磁盘驱动器本身中都存在潜在的缓存,但内核处理很多进程,所以可能不会。
每次read()
调用还必须将 CPU 从用户态更改为内核态。内存映射至少会改变。可能还会发生很多其他不那么明显的事情。这也需要时间。
系统read()
调用会更改 CPU 状态,并且可能需要磁盘 I/O。getc()
可以在用户空间缓冲整个磁盘块(或更多),因此可能 512 调用会getc()
导致内核读取单个磁盘块,并进行单个状态更改。如果您查看,stdio.h
您会发现一个常量宏,该常量应该是对磁盘上文件或系统调用的BUFSIZ
有效(磁盘块倍数)大小。read()
write()