目前我正在研究一个读取大文件并对其进行sorting的小程序。 经过一些基准testing后,我偶然发现了一个奇怪的性能问题。 当input文件变大时,输出文件的写入花费的时间比实际的sorting要长。 所以我深入了解代码,最终意识到fputs函数可能是问题。 所以我写了这个小标杆程序。
#include "stdio.h" #include "ctime" int main() { int i; const int linecount = 50000000; //Test Line with 184 byte const char* dummyline = "THIS IS A LONG TEST LINE JUST TO SHOW THAT THE WRITER IS GUILTY OF GETTING SLOW AFTER A CERTAIN AMOUNT OF DATA THAT HAS BEEN WRITTEN. hkgjhkdsfjhgk jhksjdhfkjh skdjfhk jshdkfjhksjdhf\r\n"; clock_t start = clock(); clock_t last = start; FILE* fp1 = fopen("D:\\largeTestFile.txt", "w"); for(i=0; i<linecount; i++){ fputs(dummyline, fp1); if(i%100000==0){ printf("%i Lines written.\r", i); if(i%1000000 == 0){ clock_t ms = clock()-last; printf("Writting of %i Lines took %i ms\n", i, ms); last = clock(); } } } printf("%i Lines written.\n", i); fclose(fp1); clock_t ms = clock()-start; printf("Writting of %i Lines took %i ms\n", i, ms); }
当你执行这个程序的时候,你会发现在大约14到15M的线路之后,性能明显下降,大约有2.5GB的数据。 写作需要大约3倍的时间。 2GB的门槛表示一个64位的问题,但我还没有发现任何关于在networking上。 我还testing了二进制和字符模式(例如“wb”和“w”)之间是否有区别,但是没有。 我也试图预先分配文件大小(以避免文件碎片),通过寻求预期的结束和写一个零,但也没有什么影响。
我正在运行Windows 7 64位计算机,但是我也在Windows Server 2008 64位R1计算机上进行了testing。 目前我正在testing一个NTFS文件系统超过200GB的可用空间。 我的系统有16GB的内存,所以也不应该是一个问题。 testing程序只使用大约700KB。 我之前怀疑的页面错误也非常低(整个运行时间约400页错误)。
我知道,对于这样的大数据,fwrite()函数可以更好地处理这个任务,但是现在我有兴趣了解是否还有其他的解决方法,以及为什么会发生这种情况。 任何帮助将不胜感激。
所有这一切的主要原因是Windows磁盘缓存。 然后你的程序吃所有的RAM,然后交换开始,因此,减速。 要打这些你需要:
1)使用c
标志在提交模式下打开文件:
FILE* fp1 = fopen("D:\\largeTestFile.txt", "wc");
2)使用flush
功能定期将缓冲区写入磁盘:
if(i%1000000 == 0) { // write content to disk fflush(fp1); clock_t ms = clock()-last; printf("Writting of %i Lines took %i ms\n", i, ms); last = clock(); }
这样你将使用合理数量的磁盘缓存。 速度将基本上受限于硬盘的速度。