gpt4 book ai didi

c - fwrite() 性能远低于磁盘容量

转载 作者:可可西里 更新时间:2023-11-01 11:53:59 25 4
gpt4 key购买 nike

我有一个包含 1700 万个元素的 struct 动态分配数组。为了将它保存到磁盘,我写了

fwrite(StructList, sizeof(Struct), NumStructs, FilePointer)

在后面的步骤中,我使用等效的 fread 语句读取它,即使用 sizeof(Struct)NumStructs 的计数.我预计生成的文件大约为 3.5 GB(这都是 x64)。

是否可以通过传递 sizeof(Struct) * NumStructs 作为大小和 1 作为计数来加快速度?我绞尽脑汁想知道为什么在具有 32 GB RAM(大量写入缓存)的快速计算机上写入操作可能需要 分钟。我已经运行了自制基准测试,缓存足够激进,前 800 MB 到 1 GB 的速度通常为 400 MB/秒。 PerfMon 显示它在 fwrite 期间消耗了一个内核的 100%。

我看到了问题here所以我要问的是,fwrite 中是否有一些循环可以通过告诉它写入大小为 n*s 的 1 个元素而不是大小为 n 的元素来“欺骗”以更快地运行。

编辑

我在 Release模式下运行了两次,两次我都放弃了等待。然后我在 Debug模式下运行它,因为我知道 fwrite 操作通常需要更长的时间。要写入的数据的确切大小为 4,368,892,928 字节。在所有这三种情况下,PerfMon 都显示两次突发的磁盘写入事件,间隔大约 30 秒,之后 CPU 达到一个内核的 100%。该文件此时为 73,924,608 字节。我在 fwrite 的两边都有断点,所以我知道它所在的位置。看起来肯定有什么东西卡住了,但我会让它运行一整夜看看。

编辑

把它放了一夜,它肯定卡在 fwrite 中,文件从未超过 70 MB。

最佳答案

这绝对是fwrite的问题(VS2012和2010我都试过了)

从一个标准的 C++ 项目开始,我只更改了设置以在静态链接中使用多字节字符集、x64 目标和标准库的多线程调试版本。

以下代码成功(为了简洁没有错误检查):

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

int main()
{
FILE *fp;
long long n;
unsigned char *data;

n = 4LL * 1024 * 1024 * 1024 - 1;

data = (unsigned char *)malloc(n * sizeof(unsigned char));

fp = fopen("T:\\test.bin", "wb");

fwrite(data, sizeof(unsigned char), n, fp);

fclose(fp);
}

在我机器上的调试版本中,程序在大约 1 分钟内完成(malloc 只需要几秒钟,所以这主要是 fwrite),平均消耗 30% 的 CPU。 PerfMon 显示写入完全发生在最后是一个 4 GB 的“闪存”(写入缓存)。

在 n 的赋值中将 - 1 更改为 + 1 并且您重现了问题:瞬时 100% CPU 使用率并且什么都没有写入。几分钟后,文件的大小仍然是 0 字节(回想一下我的实际代码,它设法转储了 70 MB 左右)。

这肯定是 fwrite 的问题,因为下面的代码可以很好地写入文件:

int main()
{
FILE *fp;
long long n;
long long counter = 0;
long long chunk;
unsigned char *data;

n = 4LL * 1024 * 1024 * 1024 + 1;

data = (unsigned char *)malloc(n * sizeof(unsigned char));

fp = fopen("T:\\test.bin", "wb");

while (counter < n)
{
chunk = min(n - counter, 100*1000);
fwrite(data+counter, sizeof(unsigned char), chunk, fp);
counter += chunk;
}

fclose(fp);
}

在我的机器上,这需要 45 秒而不是 1 分钟。 CPU 使用率不是恒定的,它是突发的,报告的 IO 写入比“单 block ”方法更分散。

如果速度的增加是错误的(也就是说,由于缓存),我会感到非常惊讶,因为我在编写包含所有相同数据的几个文件与包含随机数据的文件和报告的写入速度(与缓存)是一样的。所以我敢打赌,至少 fwrite 的这个实现不喜欢一次传递给它的大块。

我还测试了 fread 在 4 GB+1 的情况下关闭文件写入后立即读取并且它及时返回 - 最多几秒钟(这里没有真实数据所以我没有检查它)。

编辑

我使用 block 写入方法和 4 GB-1 文件的单个 fwrite 调用运行了一些测试(这两种方法都可以做到的最大大小)。多次运行程序(使用这样的代码打开文件,通过多次 fwrite 调用写入,关闭,然后再次打开,在一次调用中写入,然后关闭),毫无疑问, block 写入方法返回得更快。在最坏的情况下,它返回的时间是单次调用所需时间的 68%,而我最多只得到 20%。

关于c - fwrite() 性能远低于磁盘容量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21947743/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com