实验一 同步与异步write的效率比较

实验一 同步与异步write的效率比较

一、程序要求

实验要求程序必须指定输出的文件名,而该文件是否按同步方式打开,则是可以选择的。因此程序至少带一个、至多两个输入参数。程序默认从标准输入STDIN_FILENO读取输入文件,可以利用shell的输入定向功能选择具体的输入文件。

timewrite < outfile > [sync]

不得变更程序的名字和使用方法。sync参数为可选,若有则输出文件用O_SYNC打开(见课本P51的解释)。

例:

timewrite  <f1 f2     表示输出文件f2不用O_SYNC 打开。

timewrite  f1  sync <f2  表示输出文件f1用O_SYNC 打开。

程序输出write耗费的时间,注意避免计入read的时间。

二、解决方案

缓冲区

在这里插入图片描述

我们先把读出的数据放在缓冲区,计算机再直接从缓冲区中取数据,这样就可以减少磁盘的读写次数,再加上计算机对缓冲区的操作大大快于对磁盘的操作,故应用缓冲区可大大提高计算机的运行速度。缓冲区就是一块内存区, 它用在输入输出设备和CPU之间,用来缓存数据 。它 使得低速的输入输出设备和高速的CPU能够协调工作 ,避免低速的输入输出设备占用CPU,解放出CPU,使其能够高效率工作。 为了准确计算write耗费的时间,很重要的就是要避免将read的时间计入,因为I/O操作的时间通常是毫秒级的,不可以忽略。一种有效的方法是,设置一个与输入文件长度相同的缓冲区,一次性地将输入文件读入缓冲区,而后就不必再读输入文件。这样就可以有效避免计入read的时间。

设置输入缓冲区需要知道文件的长度,我们用lseek的返回值来获取长度。在按每一个给定大小的输出缓冲区计算写文件时间时,应当在开始写之前调用times(),记录下开始时间,然后在整个输入缓冲区都复制到输出文件之后,再调用times(),两次调用times()的时间间隔,就是在这个给定大小的输出缓冲区的限制下,复制整个输入文件所耗费的写时间。至于在每一次写的时候所执行的其他语句,它们相较于I/O操作,所花费的时间极小,可以忽略不计。

步骤一、打开我们要写入的文件,如果文件不存在则创建一个。设置sync参数为可选项,若有则输出文件用O_SYNC打开。

步骤二、利用lseek函数获取文件的长度,利用文件重定向,即运行参数 <f1 的作用,以STDIN_FILENO 和 STDOUT_FILENO 。

步骤三、开辟文件缓冲区。

步骤四、利用STDIN_FILENO把文件读入buff中。

步骤五、也是最关键的一步,写入。每次以固定的 buffsize 写入,所以需要写入(file length / buff size)次。考虑到最后一部分的剩余内容,所以还需要再写一次,考虑到用不同的buffsize写入的时候,需要用lseek设置文件偏移量到文件头,这样就可以重新写入了。

步骤六、运行时间比较。每次写入的时候调用times(),结束的时候再次调用times(),时间之差即为写入时间。

*系统调用times()的说明\****

\#include <sys/times.h>
clock_t times(struct tms *buf);
struct tms {
	clock_t tms_utime; 	/* 记录进程除系统调用外所使用的CPU时间 */
	clock_t tms_stime; 	/* 记录进程的系统调用所使用的CPU时间 */
 	clock_t tms_cutime; 	/* 记录子进程除系统调用外所使用的CPU时间 */
    clock_t tms_cstime; 	/* 记录子进程的系统调用所使用的CPU时间 */
};

times函数的返回值是进程迄今为止的存活时间。所有时间都是以“滴答”为单位的,函数 sysconf(_SC_CLK_TCK)可获得所运行系统每秒的滴答数

三、代码
#include<stdio.h>
#include<fcntl.h>
#include<sys/times.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<stdlib.h>
#include<errno.h>
#include<stdarg.h>

int main(int argc,char* argv[])
{
    //参数检查
    if(argc<2||argc>3){
        printf("argv error: ./timewrite<f1 f2 or ./timewrite f1 sync < f2");
    }    
    if(argc==3 && strcmp(argv[2],"sync")!=0){
        printf("argv[2] error: ./timewrite f1 sync<f2");
    }

    int fd;

    //打开文件
    if(argc==2) //异步打开文件
    {
        if((fd=open(argv[1],O_RDWR|O_CREAT,0777))<0){
            printf("can't open");
            exit(0);
        }
    }else //同步打开文件
        {
             if((fd=open(argv[1],O_RDWR|O_CREAT|O_TRUNC|O_SYNC,0777))<0){
                printf("can't open");
                exit(0);
             }  
        }
   

    //获取文件长度
    long int length;
    if((length = lseek(STDIN_FILENO,0,SEEK_END))<0){
        printf("lseek error");
        exit(0);
    }

    //开辟文件长度大小的缓冲区
    char * buff;
    buff = (char*)malloc(sizeof(char)*length);

    //设置文件偏移量为开头
    if(lseek(STDIN_FILENO,0,SEEK_SET)==-1){
        printf("lseek error");
        exit(0);
    }

    //把文件读入到buff中
    if(read(STDIN_FILENO,buff,length)<0){
        printf("read error");
        exit(0);
    }

    //返回每秒时钟的滴答数
    int ticks = sysconf(_SC_CLK_TCK);
    
    //写文件,并计算效率
    clock_t clockstart,clockend;
    struct tms tmsStart,tmsEnd;
    int buffsize;
    for(buffsize=1024;buffsize<=131072;buffsize *= 2){
 
         printf("\n\nBuffsize:%d\n",buffsize);

         //每次写入前,定位到文件头
        if(lseek(fd,0,SEEK_SET)==-1) printf("lseek error");

        clockstart = times(&tmsStart);

        int count = length/buffsize;  //写入次数
        for(int i=0;i<count;i++){
            if(write(fd,buff+i*buffsize,buffsize)!=buffsize){
                printf("write error");
                exit(0);
            }
        }

        int remain = length - buffsize*count;  //剩余内容
        //写入剩余内容
        if(remain){
            if(write(fd,buff+count*buffsize,remain)!=remain){
                printf("write error");
                exit(0);
            }
            count++;
        }

        clockend = times(&tmsEnd);

        printf("clock used = %d\n",clockend-clockstart);
        printf("tms_utime = %d\n",tmsEnd.tms_utime-tmsStart.tms_utime);
        printf("tms_stime = %d\n",tmsEnd.tms_stime-tmsStart.tms_stime);
        printf("tms_cutime = %d\n",tmsEnd.tms_cutime-tmsStart.tms_cutime);
        printf("tms_cstime = %d\n",tmsEnd.tms_cstime-tmsStart.tms_cstime);
    }
    return 0;
}

三、运行结果

在这里插入图片描述在这里插入图片描述

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值