f中的fgetc/fputc和fread/fwrite之间的速度比较

pra*_*km 8 c performance

所以(只是为了好玩),我只是想编写一个C代码来复制文件.我四处看看似乎从流调用中读取的所有函数fgetc()(我希望这是真的吗?),所以我使用了这个函数:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define FILEr "img1.png"
#define FILEw "img2.png"
main()
{
    clock_t start,diff;
    int msec;
    FILE *fr,*fw;
    fr=fopen(FILEr,"r");
    fw=fopen(FILEw,"w");
    start=clock();
    while((!feof(fr)))
        fputc(fgetc(fr),fw);
    diff=clock()-start;
    msec=diff*1000/CLOCKS_PER_SEC;
    printf("Time taken %d seconds %d milliseconds\n", msec/1000, msec%1000);
    fclose(fr);
    fclose(fw);
}
Run Code Online (Sandbox Code Playgroud)

在2.10Ghz core2Duo T6500 Dell inspiron笔记本电脑上,这个文件的运行时间为140毫秒.但是,当我尝试使用fread/时fwrite,我会减少运行时间,因为我不断增加st为每个调用传输的字节数(即以下代码中的变量),直到它在10ms左右达到峰值!这是代码:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define FILEr "img1.png"
#define FILEw "img2.png"
main()
{
    clock_t start,diff;
    // number of bytes copied at each step
    size_t st=10000;
    int msec;
    FILE *fr,*fw;
    // placeholder for value that is read
    char *x;
    x=malloc(st);
    fr=fopen(FILEr,"r");
    fw=fopen(FILEw,"w");
    start=clock();
    while(!feof(fr))
     {
        fread(x,1,st,fr);
        fwrite(x,1,st,fw);
     }
    diff=clock()-start;
    msec=diff*1000/CLOCKS_PER_SEC;
    printf("Time taken %d seconds %d milliseconds\n", msec/1000, msec%1000);
    fclose(fr);
    fclose(fw);
    free(x);
}
Run Code Online (Sandbox Code Playgroud)

为什么会这样?即如果fread实际上是多次调用fgetc那么为什么速度差?编辑:指定"增加字节数"是指st第二个代码中的变量

TJD*_*TJD 16

fread()不是要求fgetc()读取每个字节.

它的行为就像fgetc()重复调用一样,但它可以直接访问从中fgetc()读取的缓冲区,因此可以直接复制大量数据.

  • 为"好像"+1.您可以通过解释"似乎规则"如何应用于C语言中的所有内容来改进答案. (4认同)
  • 用户空间libc stdio库与FUSE或正在访问的底层文件系统/设备无关.除非禁用缓冲,否则它将始终以完全缓冲模式运行.即使禁用了缓冲,非病态错误的`fread`实现也永远不会重复调用`fgetc`,但会对所请求长度的部分执行单个`read`操作,而这些部分无法从现有的用户空间缓冲区中获取. (2认同)

seh*_*ehe 6

您忘记了文件缓冲(inode,dentry和页面缓存).

在运行之前清除它们:

echo 3 > /proc/sys/vm/drop_caches
Run Code Online (Sandbox Code Playgroud)

背景资料:

基准测试是一门艺术.请参阅bonnie++,iozonephoronix进行适当的文件系统基准测试.作为一个特征,bonnie++不允许基准的写入量小于可用系统内存的2倍.

为什么?

(回答:缓冲效果!)

  • 是的.操作可能会在短时间内测试两个版本.第一次运行将填充缓存,第二次运行可以期望文件在OS缓冲区中完全缓冲,因此操作不需要I/O. (5认同)