【问题标题】:Read/write program in c that copies file and i think its taking too long to copy复制文件的c中的读/写程序,我认为复制时间太长
【发布时间】:2020-10-25 17:33:26
【问题描述】:

第一个代码使用预设缓冲区,当我将缓冲区设置为 512 字节时,我需要复制 100MB 文件大约需要 1 秒,但是当我使用 1 字节缓冲区时,复制 100MB 文件需要 3 分钟以上,另一方面我有其他使用 fread 和 fwrite 函数的代码,它在 512 字节缓冲区上快了大约 0.5 秒,但他只需要大约 13 秒来复制 100 mb 文件和 1 字节缓冲区有人可以看到使用系统调用的代码中的任何错误(读,写,打开)


1.使用(读取、写入...)的代码

int main(int argc, char* argv[])
{
    char sourceName[20], destName[20], bufferStr[20];
    int f1, f2, fRead;
    int bufferSize = 0;
    char* buffer;

    bufferSize = atoi(argv[3]);

    buffer = (char*)calloc(bufferSize, sizeof(char));
    strcpy(sourceName, argv[1]);
   
    f1 = open(sourceName, O_RDONLY);
    if (f1 == -1)
        printf("something's wrong with oppening source file!\n");
    else
        printf("file opened!\n");

    strcpy(destName, argv[2]);
    f2 = open(destName, O_CREAT | O_WRONLY | O_TRUNC | O_APPEND);
    if (f2 == -1)
        printf("something's wrong with oppening destination file!\n");
    else
        printf("file2 opened!");

    fRead = read(f1, buffer, sizeof(char));
    while (fRead != 0)
    {
        write(f2, buffer, sizeof(char));
        fRead = read(f1, buffer, sizeof(char);
    }
    close(f1);
    close(f2);


    return 0;
}

2。使用的代码(fread, fwrite...)

int main(int argc, char* argv[]) {
    FILE* fsource, * fdestination;

    char sourceName[20], destinationName[20], bufferSize[20];
    //scanf("%s %s %s", sourceName, destinationName, bufferSize);
    strcpy(sourceName, argv[1]);
    strcpy(destinationName, argv[2]);
    strcpy(bufferSize, argv[3]);
    int bSize = atoi(bufferSize);
    printf("bSize = %d\n", bSize);
    fsource = fopen(sourceName, "r");
    if (fsource == NULL)
        printf("read file did not open\n");
    else
        printf("read file opened sucessfully!\n");
    
    fdestination = fopen(destinationName, "w");
    if (fdestination == NULL)
        printf("write file did not open\n");
    else
        printf("write file opened sucessfully!\n");

    char *buffer = (char*)calloc(bSize, sizeof(char));
    int flag;

    printf("size of buffer: %d", bSize);

    while (0 < (flag = fread(buffer, sizeof(char), bSize, fsource)))
        fwrite(buffer, sizeof(char), bSize, fdestination);
   

    fclose(fsource);
    fclose(fdestination);
    return 0;
}

编辑: 这些是我对缓冲区的测量 我对每个缓冲区和每个文件 malaDat(1byte)、srednjaDar(100MB)、velikaDat(1GB) 进行了 20 次测量

【问题讨论】:

    标签: c unix copy


    【解决方案1】:

    旁注:sizeof(char)总是1根据定义。所以,不要使用sizeof(char)——这是不受欢迎的。而且,我认为这增加了你的困惑。

    因为您的示例使用read/write is 使用sizeof(char) 作为count(第三个参数),它只在每次循环迭代中传输 一个 字节(即非常慢)。

    猜测一下,我认为您将 read/writecountfread/fwritesize 参数混淆了。

    你想要的是:

    while (1) {
        fRead = read(f1, buffer, bufferSize);
        if (fRead <= 0)
            break;
        write(f2, buffer, fRead);
    }
    

    另外,fread/fwrite [可能] 会选择一个最佳缓冲区大小 [可能是 4096]。你可以使用setbuf 来改变它。

    我[从某处的一些文档中]发现,对于大多数文件系统[至少在 linux 下],最佳传输大小是 64KB(即64 * 1024)。

    所以,尝试设置bufferSize = 64 * 1024

    IIRC,有一个ioctl/syscall可以返回最优大小的值,但是忘记是什么了。


    更新:

    好的,但是当我选择 1byte 缓冲区时,它仍然太慢,复制需要超过 40 分钟。

    当然,1 字节的传输 [缓冲区] 大小会产生可怕的结果。

    当我在同一个缓冲区中使用 fread 和 fwrite 时,它​​花费的时间更少,大约需要 3 分钟,为什么会这样?

    文件有多大(即各自的传输速率 [以 MB/秒为单位])?我假设您的系统可以以 10 MB/秒的速度传输 [保守的 - 30 MB/秒 [最低] 对于最近的新系统]。那么,这是 600 MB/分钟,文件大约是 1.8 GB?

    当您为read/write 指定一个 1 字节的传输/缓冲区大小时,他们完全按照您告诉他们的操作。传输 1 个字节。因此,您将执行约 20 亿次 read 系统调用和 20 亿次 write 系统调用!!!

    系统调用通常很慢。

    stdio 流有一个内部 缓冲区。这设置为最佳大小,例如:4096。

    fread [and fwrite] 将通过 [internally] read/write 以 4096 的计数来填充/排出 缓冲区。

    所以,fread/fwrite 正在执行 4096 次 更少 系统调用。因此,只有大约 470,000 个系统调用。相当减少。

    internal 缓冲区到 your 缓冲区的传输一次完成一个字节,但这只是一个短/快@ 987654346@ 操作完全在用户空间应用程序内完成。这比按字节发出系统调用快很多

    因此,您传递给fread/fwrite 的传输大小不会影响其内部缓冲区的大小。

    fread/fwrite 仅在流的 internal 缓冲区为空/满时分别发出 read/write 系统调用来补充/排出缓冲区,无论您在 fread/fwrite 调用中给出的长度如何.

    如果您想减慢 fread/fwrite 的速度,请查看 setbuf 等的手册页。人。并做:

    setbuffer(fsource,NULL,1);
    setbuffer(fdestination,NULL,1);
    

    更新 #2:

    所以这完全正常吗?我问是因为这是我的大学任务来进行测量,我的同事得到的系统调用结果比用户调用慢了大约 2 分钟,我得到的结果要慢得多

    如果你和他们核实一下,我敢打赌他们正在使用更大的缓冲区大小。

    请记住,您原来的 read/write 代码有一个错误,它一次只能传输一个字节,无论您将 bufferSize 设置为 [从命令行]。

    这就是我更改原始帖子中的循环的原因。

    超额完成...

    查看O_DIRECT 以获得open。如果您使用posix_memalign 而不是malloc,您可以强制缓冲区对齐为允许O_DIRECT 工作的页面大小(4096) 的倍数。并且,将缓冲区大小设置为页面大小的倍数。

    此选项绕过read/write系统调用从您的用户空间从内核的内部页面/文件系统缓存复制/传输操作,并具有DMA H/W传输直接到/从你的缓冲区。

    另外,考虑添加O_NOATIME

    此外,还有一个 linux 系统调用专门设计用于绕过所有用户空间内存/缓冲,让内核执行文件到文件的复制。它是sendfile,但它类似于memcpy,但使用文件描述符、偏移量和长度。

    而且,访问文件数据的最快方法是使用mmap。查看我的答案:

    1. How does mmap improve file reading speed?
    2. read line by line in the most efficient way *platform specific*

    【讨论】:

    • 好的,但是当我选择 1byte 缓冲区时,它仍然太慢,复制需要超过 40 分钟
    • 当我在同一个缓冲区中使用 fread 和 fwrite 时,它​​花费的时间更少,大约需要 3 分钟,为什么会这样?
    • 所以这完全正常吗?我之所以问,是因为这是我的大学任务来做这个测量,我的同事得到的系统调用结果比用户调用慢了大约 2 分钟,我得到的结果要慢得多
    • 查看以秒为单位的测量表
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-22
    • 1970-01-01
    • 2021-02-28
    • 2017-09-02
    • 2014-01-26
    相关资源
    最近更新 更多