第十三章
关于测定类的题目暂时跳过
13-1 使用shell内嵌的time命令,测算程序清单4-1 copy.c在当前环境下的用时。
a)使用不同的文件缓冲区大小进行试验。编译应用程序使用-DBUF_SIZE=NBYTES选项可以设置缓冲区大小。
b)对open的系统调用加入O_SYNC标志,针对大小不同的缓冲区,速度存在多大差异?
c)在一系列的文件系统中,例如ext3、XFS、Btrfs和JFS中执行这些测试,结果相同吗?当缓冲区大小变大时,用时趋势相同吗?
这里就不在验证了。不过可以肯定的是,read和write的性能和BUF_SIZE的大小是正相关的,当BUF_SIZE达到一定值后,几乎达到最优性能。
第二条,加入O_SYNC会导致性能降低,缓冲区越小降低的越厉害。
第三条,结果不同。不同的系统对调用到写入磁盘有不同的实现形式,这将导致性能差异。缓冲区增大时,趋势相同。因为过小的缓冲区会带来更多的系统调用和I/O开销。
13-2 测定filebuff/write_bytes.c程序在不同缓冲区以及文件系统大小下的用时。
这里不再测定了。理论上来说缓冲区越大用时越少。
13-3 如下语句执行的效果是什么?
fflush(fp);
fsync(fileno(fp));
强制刷新stdio缓冲区到内核缓冲区。然后强制将内核缓冲区数据写入磁盘。
13-4 下面的代码在标准输出和重定向到文件输出的结果顺序不同,为什么?
printf("If I had more time, \n");
write(STDOUT_FILENO, "I balabalaba.\n", 14);
这是因为当输出是终端时,每次遇到\n就会刷新stdio的缓冲区,所以内核缓冲区在之后才会接受第二句的内容。如果不是终端的话,而是文件,printf不会遇到\n刷新缓冲区,所以内核缓冲区可能首先接收到第二句的内容。
13-5 实现tail命令。该命令打印文件最后10行内容。
程序比较容易实现,通过lseek偏移至文件末尾,然后倒序读内容,读满特定个数个换行符'\n'之后,程序从当前位置将后面所有的内容度读入缓冲区,并一次性输出。下面是具体实现:
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
int lastLine = 10;
char * path;
if (argc == 4 && strcmp(argv[1], "-n") == 0)
{
lastLine = atoi(argv[2]);
path = argv[3];
}
else if(argc == 2){
path = argv[1];
}
else{
printf("参数错误\n");
return -1;
}
int fd = open(path, O_RDONLY);
int end = lseek(fd, 0, SEEK_END);
int count = 0;
while(count < lastLine){
char buff;
int ret = lseek(fd, -1, SEEK_CUR);
if(ret < 0) break;
read(fd, &buff, 1);
lseek(fd, -1, SEEK_CUR);
if(buff == '\n'){
count ++;
}
}
int offset = lseek(fd, 0, SEEK_CUR);
char * buff = malloc(end - offset);
read(fd, buff, end - offset);
printf("%s\n", buff + 1);
return 0;
}
使用下面的命令编译运行代码:
gcc 13-5.c && ./a.out -n 5 13-5.c
之后,我们可以看到程序显示了文件最后的5行内容:
char * buff = malloc(end - offset);
read(fd, buff, end - offset);
printf("%s\n", buff + 1);
return 0;
}