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

我有一个1700万个元素的structdynamic分配数组。 把它保存到磁盘,我写

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

在后面的步骤中,我使用等价的fread语句读取它,即使用sizeof(Struct)NumStructs的数量。 我期望得到的文件将约3.5 GB(这是所有x64)。

是否有可能传递sizeof(Struct) * NumStructs作为大小和1作为计数来加速? 我为什么写操作可能需要几分钟的时间在32 GB的RAM(大量写caching)的快速计算机上摸不着头脑。 我已经运行了自制基准testing,并且caching足够积极,以前的800 MB到1 GB的典型值为400 MB /秒。 PerfMon显示,在fwrite期间它正在占用一个内核的100%。

我在这里看到了这个问题,所以我要问的是,fwrite中是否有一些循环可以通过告诉它写入1个大小为n * s的元素而不是n个大小为s的元素来“加速”。

编辑

我在释放模式下跑了两次,两次都放弃了等待。 然后我以debugging模式运行它,知道fwrite操作通常会花费更长的时间。 要写入的数据的确切大小是4,368,892,928字节。 在这三种情况下,PerfMon都会显示两次间隔30秒的磁盘写入活动,之后CPU将达到100%的一个内核。 该文件是在这一点73,924,608字节。 我在fwrite任何一方都有断点,所以我知道它就在那里。 看起来似乎有些东西卡住了,但是我会把它放在一夜之间去看看。

编辑

离开这一夜,它肯定挂在fwrite ,文件永远不会超过70 MB。

这肯定是fwrite一个问题(我试过VS2012和2010)。

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

下面的代码成功(没有错误检查简洁):

 #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(写入缓存)的“闪存”。

- 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写入比“单块”方法更分散。

如果速度增加是错误的(即由于缓存),我会感到惊讶,因为在编写包含所有相同数据的文件之前,我已经完成了测试,包含随机数据的文件和报告的写入速度(使用缓存)是一样。 所以我敢打赌,至少这个fwrite实现不像一次传给它的大块。

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

编辑

我用chunk-write方法和4 GB-1文件的单个fwrite调用(两种方法都可以执行的最大尺寸)运行了一些测试。 多次运行程序(使用代码打开文件,使用多个fwrite调用写入,关闭,然后再次打开,单次调用,关闭),毫无疑问,块写入方法返回的速度更快。 在最坏的情况下,单次呼叫所花费的时间为68%,最多只有20%。

这不是fwrite一个问题 ,但意图(尽管承认不冷酷 )的行为:

fwrite()函数将从由ptr指向的数组开始,将大小由size指定的nitems元素写入到stream指向的流中。 对于每个对象,应该调用fputc()函数的size调用,从数组中取值(按顺序)

所以基本上,通过正确使用fwrite 而不会作弊 ,您正在向fputc请求数十亿次调用。
考虑到上述要求,很明显,为了使其正常工作,您如何作弊。