本文通过strace跟踪 fread 和 read 系统调用的方式探究它们的性能问题
1. fread
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fp = NULL;
char buf[1024*4*10];
if ((fp = fopen("LICENSE", "rb")) == NULL)
{
perror("fopen");
return -1;
}
fread(buf, 1023, 1, fp);
// fread(buf, 4096*1-1, 1, fp);
// fread(buf, 4096*3+1, 1, fp);
fclose(fp);
return 0;
}
- fread(buf, 1023, 1, fp);
- fread(buf, 4096*1-1, 1, fp);
- fread(buf, 4096*3+1, 1, fp);
从以上测试结果可以看出,fread最多调用两次read系统调用(需要一次read读空才能确定读完了),而且每次读的大小都是页的整数倍(4k * n)
2. read
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
char buf[1024*4*10];
int fd;
if ((fd = open("LICENSE", O_RDONLY)) == -1 )
{
perror("open");
return -1;
}
read(fd, buf, 10);
// read(fd, buf, 1023);
// read(fd, buf, 4096*1-1);
// read(fd, buf, 4096*9+4);
fclose(fp);
return 0;
}
- read(fd, buf, 10);
- read(fd, buf, 1023);
- read(fd, buf, 4096*1-1);
- read(fd, buf, 4096*9+4);
从以上测试结果可以看出,当调用read时传入的size多大时,就会读取多大
3. 实例:
分别通过read和fread读完一个文件(大小为 6751字节)
- read()
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#define SIZE 1024
int main()
{
char buf[SIZE];
int fd;
if ((fd = open("LICENSE", O_RDONLY)) == -1 )
{
perror("open");
return -1;
}
while ( (n = read(fd, buf, SIZE) > 0) );
fclose(fp);
return 0;
}
read系统调用执行了8次,前7次能正确读到数据,最后一次因为数据已读完,所以返回失败(原因:6751 = 1024 * 6 + 607)
- fread()
#include <stdio.h>
#include <stdlib.h>
#define SIZE 1024
int main()
{
FILE *fp = NULL;
char buf[SIZE];
if ((fp = fopen("LICENSE", "rb")) == NULL)
{
perror("fopen");
return -1;
}
while ( (n = fread(buf, SIZE, 1, fp) > 0) )
write(STDOUT_FILENO, &n, 1);
fclose(fp);
return 0;
}
从以上结果可以看出,只调用了3次read系统调用,因为我们调用fread的时传入的size=1024,所以fread底层调用read时按页4k读取,但是并不是每次调用fread都会调用read系统调用,是因为有缓存,只有缓存读完了,才会继续从磁盘读
4. 总结:由于fread缓存的存在,多次读取性能确实可以优于read;但如果只是单次读取,还是read更快,毕竟fread底层调用的还是read。